Gmock - matching structures
Asked Answered
O

5

23

How can I match value of an element in a union for an input argument e.g - if I mock a method with the following signatiure -

    struct SomeStruct
    {   
        int data1;
        int data2; 
    };

    void SomeMethod(SomeStruct data);

How can I match that mock for this method was called with correct value in argument?

Optimal answered 29/5, 2014 at 16:30 Comment(2)
Did you mean to define SomeStruct as a union?Exequies
yes sorry structure or a union , is it possible?Optimal
O
34

After reading through the Google mock documentation in detail, I solved my problem as documented in Defining Matchers section. (An example would have been great!)

So the solution is to use the MATCHER_P macros to define a custom matcher. So for the matching SomeStruct.data1 I defined a matcher:

MATCHER_P(data1AreEqual, ,"") { return (arg.data1 == SomeStructToCompare.data1); }

to match it in an expectation I used this custom macro like this:

EXPECT_CALL(someMock, SomeMethod(data1AreEqual(expectedSomeStruct)));

Here, expectedSomeStruct is the value of the structure.data1 we are expecting.

Note that, as suggested in other answers (in this post and others), it requires the unit under test to change to make it testable. That should not be necessary! E.g. overloading.

Optimal answered 3/6, 2014 at 11:45 Comment(2)
Yeah, much agreed - the gmock cheat sheet is great unless you want to actually see an example in action, which is usually the best/easiest way to figure out what to do. You example MATCHER here was exactly what helped me solve my problem!Elmaleh
hi please tell me how to mock a method methodx(param1* p1,param1* p2,tm * tm1) and test value "tm_isdst" in tm struct is 0. i want to know how to write a macher for thatDianemarie
S
20

If there a need to explicitly test for specific value of just one field of a struct (or one "property" of a class), gmock has a simple way to test this with the "Field" and "Property" definitions. With a struct:

EXPECT_CALL( someMock, SomeMethod( Field( &SomeStruct::data1, Eq(expectedValue) )));

Or, alternatively if we have SomeClass (intead of SomeStruct), that has private member variables and public getter functions:

EXPECT_CALL( someMock, SomeMethod( Property( &SomeClass::getData1, Eq(expectedValue) )));
Swindle answered 5/12, 2016 at 12:42 Comment(1)
Friendly reminder that implicit equality matching is discouraged, i.e. Prefer Field( &SomeStruct::data1, Eq(expectedValue)). Not doing so resulted in compiler errors in my case.Eburnation
E
7

Google provides some good documentation on using gmock, full of example code. I highly recommend checking it out:

https://github.com/google/googletest/blob/master/googlemock/docs/cook_book.md#using-matchers

As you pointed out, a default equality operator (==) isn't automatically created for class types (including PODs). Since this operator is used by gmock when matching parameters, you would need to explicitly define it in order to use the type as you would any other type (as seen below):

    // Assumes `SomeMethod` is mocked in `MockedObject`
    MockedObject foo;
    SomeStruct expectedValue { 1, 2 };

    EXPECT_CALL(foo, SomeMethod(expectedValue));

So, the most straightforward way of dealing with this is to define an equality operator for the struct:

struct SomeStruct
{   
    int data1;
    int data2; 

    bool operator==(const SomeStruct& rhs) const
    {
        return data1 == rhs.data1
            && data2 == rhs.data2;
    }
};

If you don't want to go that route, you can consider using the Field matcher to match the parameter based on the values of its member variables. (If a test is interested in comparing equality between instances of the struct, though, it's a good indication that other code will be interested as well. So it'd likely be worthwhile to just define an operator== and be done with it.)

Exequies answered 29/5, 2014 at 21:7 Comment(7)
that does not work ! I would not have asked if it was as simple!Optimal
Can you clarify what you mean, that it "does not work?" Post the code that isn't working so that we can provide better guidance.Exequies
try it you get - you get "no binary == operator found "as there is no way to compare structs!Optimal
My apologies - for some reason I thought C++ generated a default equality operator for POD types. I'll update my answer.Exequies
Hi , the solution although will work also has a sideeffect of adding new logic to uut. I have posted an alternative.Optimal
Fair enough. I practice TDD, so my tests are always influencing my design.Exequies
Yes, sometimes code is not written in a testable way or gets tangled, so modifying source code (there too) might be the first stepPreach
P
7

Maybe useless as the question has been answered long time ago but here is a solution that works with any structure and which does not use MATCHER or FIELD.

Suppose we are checking: methodName(const Foo& foo):

using ::testing::_;

struct Foo {
    ...
    ...
};

EXPECT_CALL(mockObject, methodName(_))
    .WillOnce([&expectedFoo](const Foo& foo) {
        // Here, gtest macros can be used to test struct Foo's members
        // one by one for example (ASSERT_TRUE, ASSERT_EQ, ...)
        ASSERT_EQ(foo.arg1, expectedFoo.arg1);
    });
Pneumatograph answered 14/5, 2020 at 22:6 Comment(0)
D
5

This is basically answered above but I want to give you one more good example:

// some test type
struct Foo {
    bool b;
    int i;
};

// define a matcher if ==operator is not needed in production
MATCHER_P(EqFoo, other, "Equality matcher for type Foo") {
    return std::tie(arg.b, arg.i) == std::tie(other.b, other.i);
}

// example usage in your test
const Foo test_value {true, 42};
EXPECT_CALL(your_mock, YourMethod(EqFoo(test_value)));
Didst answered 29/7, 2019 at 15:52 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.