Gtest Mock_method

0 views
Skip to first unread message

Pang Murdock

unread,
Aug 4, 2024, 3:37:23 PM8/4/24
to riagrapwencha
Apparentlythis feature was not implemented in 1.8.I cloned the most recent version of googletest here.Having checked the topmost CMakeLists.txt on master branch I see thatcurrent gtest version on master is:set(GOOGLETEST_VERSION 1.10.0)

It sounds like the MOCK_METHOD macro is not defined. Have you set up your include path correctly and added the #include "gmock/gmock.h" directive at the top of your file? You are also missing a public access specifier and the number of arguments is wrong for the function.


Note: Google Mock lives in the testing name space. For readability, it is recommended to write using ::testing::Foo; once in your file before using the name Foo defined by Google Mock. We omit such using statements in this page for brevity, but you should do it in your own code.


You must always put a mock method definition (MOCK_METHOD*) in a public: section of the mock class, regardless of the method being mocked being public, protected, or private in the base class. This allows ON_CALL and EXPECT_CALL to reference the mock function from outside of the mock class. (Yes, C++ allows a subclass to change the access level of a virtual function in the base class.) Example:


Note: if you don't mock all versions of the overloaded method, the compiler will give you a warning about some methods in the base class being hidden. To fix that, use using to bring them in scope:


In this case, instead of sharing a common base class with the real class, your mock class will be unrelated to the real class, but contain methods with the same signatures. The syntax for mocking non-virtual methods is the same as mocking virtual methods:


Next, you need a way to say that you want to use ConcretePacketStream in production code, and use MockPacketStream in tests. Since the functions are not virtual and the two classes are unrelated, you must specify your choice at compile time (as opposed to run time).


One way to do it is to templatize your code that needs to use a packet stream. More specifically, you will give your code a template type argument for the type of the packet stream. In production, you will instantiate your template with ConcretePacketStream as the type argument. In tests, you will instantiate the same template with MockPacketStream. For example, you may write:


If a method of mock_foo other than DoThis() is called, it will be reported by Google Mock as a warning. However, if you rewrite your test to use NiceMock instead, the warning will be gone, resulting in a cleaner test output:


Mocking concrete classes directly is problematic as it creates a tight coupling between the class and the tests - any small change in the class may invalidate your tests and make test maintenance a pain.


Some people worry that if everyone is practicing this technique, they will end up writing lots of redundant code. This concern is totally understandable. However, there are two reasons why it may not be the case:


Now you want to mock this interface such that you can set expectations on it. However, you also want to use FakeFoo for the default behavior, as duplicating it in the mock object is, well, a lot of work.


When using testing doubles (mocks, fakes, stubs, and etc), sometimes their behaviors will differ from those of the real objects. This difference could be either intentional (as in simulating an error such that you can test the error handling code) or unintentional. If your mocks have different behaviors than the real objects by mistake, you could end up with code that passes the tests but fails in production.


You can use the delegating-to-real technique to ensure that your mock has the same behavior as the real object while retaining the ability to validate calls. This technique is very similar to the delegating-to-fake technique, the difference being that we use a real object instead of a fake. Here's an example:


With this, Google Mock will verify that your code made the right calls (with the right arguments, in the right order, called the right number of times, etc), and a real object will answer the calls (so the behavior will be the same as in production). This gives you the best of both worlds.


Ideally, you should code to interfaces, whose methods are all pure virtual. In reality, sometimes you do need to mock a virtual method that is not pure (i.e, it already has an implementation). For example:


Google Mock matchers are statically typed, meaning that the compiler can catch your mistake if you use a matcher of the wrong type (for example, if you use Eq(5) to match a string argument). Good for you!


To disambiguate overloaded functions with the same number of arguments but different argument types, you may need to specify the exact type of a matcher, either by wrapping your matcher in Matcher(), or using a matcher whose type is fixed (TypedEq, An(), etc):


Sometimes it's not enough to match the arguments individually. For example, we may want to say that the first argument must be less than the second argument. The With() clause allows us to match all arguments of a mock function as a whole. For example,


Have you noticed that a matcher is just a fancy predicate that also knows how to describe itself? Many existing algorithms take predicates as arguments (e.g. those defined in STL's header), and it would be a shame if Google Mock matchers are not allowed to participate.


Google Mock provides a built-in set of matchers. In case you find them lacking, you can use an arbitray unary predicate function or functor as a matcher - as long as the predicate accepts a value of the type you want. You do this by wrapping the predicate inside the Truly() function, for example:


Often a mock function takes a reference to object as an argument. When matching the argument, you may not want to compare the entire object against a fixed object, as that may be over-specification. Instead, you may need to validate a certain member variable or the result of a certain getter method of the object. You can do this with Field() and Property(). More specifically,


C++ functions often take pointers as arguments. You can use matchers like IsNull(), NotNull(), and other comparison matchers to match a pointer, but what if you want to make sure the value pointed to by the pointer, instead of the pointer itself, has a certain property? Well, you can use the Pointee(m) matcher.


What if you have a pointer to pointer? You guessed it - you can use nested Pointee() to probe deeper inside the value. For example, Pointee(Pointee(Lt(3))) matches a pointer that points to a pointer that points to a number less than 3 (what a mouthful...).


Sometimes you want to specify that an object argument has a certain property, but there is no existing matcher that does this. If you want good error messages, you should define a matcher. If you want to do it quick and dirty, you could get away with writing an ordinary function.


Sometimes an STL container (e.g. list, vector, map, ...) is passed to a mock function and you may want to validate it. Since most STL containers support the == operator, you can write Eq(expected_container) or simply expected_container to match a container exactly.


Sometimes, though, you may want to be more flexible (for example, the first element must be an exact match, but the second element can be any positive number, and so on). Also, containers used in tests often have a small number of elements, and having to define the expected container out-of-line is a bit of a hassle.


ElementsAre() and UnorderedElementsAre() are overloaded to take 0 to 10 arguments. If more are needed, you can place them in a C-style array and use ElementsAreArray() or UnorderedElementsAreArray() instead:


Under the hood, a Google Mock matcher object consists of a pointer to a ref-counted implementation object. Copying matchers is allowed and very efficient, as only the pointer is copied. When the last matcher that references the implementation object dies, the implementation object will be deleted.


Therefore, if you have some complex matcher that you want to use again and again, there is no need to build it everytime. Just assign it to a matcher variable and use that variable repeatedly! For example,


There are basically two constructs for defining the behavior of a mock object: ON_CALL and EXPECT_CALL. The difference? ON_CALL defines what happens when a mock method is called, but doesn't imply any expectation on the method being called. EXPECT_CALL not only defines the behavior, but also sets an expectation that the method will be called with the given arguments, for the given number of times (and in the given order when you specify the order too).


Since EXPECT_CALL does more, isn't it better than ON_CALL? Not really. Every EXPECT_CALL adds a constraint on the behavior of the code under test. Having more constraints than necessary is baaad - even worse than not having enough constraints.


The answer, lies in what a test should verify. A good test verifies the contract of the code. If a test over-specifies, it doesn't leave enough freedom to the implementation. As a result, changing the implementation without breaking the contract (e.g. refactoring and optimization), which should be perfectly fine to do, can break such tests. Then you have to spend time fixing them, only to see them broken again the next time the implementation is changed.


So use ON_CALL by default, and only use EXPECT_CALL when you actually intend to verify that the call is made. For example, you may have a bunch of ON_CALLs in your test fixture to set the common mock behavior shared by all tests in the same group, and write (scarcely) different EXPECT_CALLs in different TEST_Fs to verify different aspects of the code's behavior. Compared with the style where each TEST has many EXPECT_CALLs, this leads to tests that are more resilient to implementational changes (and thus less likely to require maintenance) and makes the intent of the tests more obvious (so they are easier to maintain when you do need to maintain them).

3a8082e126
Reply all
Reply to author
Forward
0 new messages