Google C ++ unit testing framework GoogleTest --- Introduction to Google Mock-concepts and basic syntax, javamock framework

Source: Internet
Author: User

Google C ++ unit testing framework GoogleTest --- Introduction to Google Mock-concepts and basic syntax, javamock framework

Just yesterday, I finally made a gtest sharing. My pre-research work has finally ended, and I feel that it is not long before I resign. After all, I focused on java for two hundred years, I want to say goodbye to my internship ..

This is an introduction to GoogleMock and will be accompanied by an example of its own.

1. What is Google C ++ Mocking Framework?

When you write a prototype or test, you cannot fully rely on real objects. A mock object implements the same interface as a real object, but how does one use it when you specify it at runtime? What should it do? (Which methods will be called? In what order? How many times? What are the parameters? What will they return? )

Note: It is easy to confuse forged objects and simulated objects. Fakes and mock actually mean very different things in the test-driven development (TDD) community:

  • Fake (pseudo objects) has a work implementation, but usually takes some shortcuts (which may make the operation cheaper), which makes them not suitable for production. The file system in the memory will be an example of fake.
  • Mock (simulators) are intended programming objects that form the specifications of the calls they expect to receive.

If all these are too abstract for you, don't worry-the most important thing to remember is a simulation that allows you to check the interaction between yourself and the caller. Once you start using mock, the difference between fake and mock will become clearer.

The Google C ++ Mocking framework (or Google Mock for short) is a library (sometimes called a "framework" to make it sound cool) used to create simulation classes and use them. It is for C ++, just like jMock and EasyMock for Java.

Using Google Mock involves three basic steps:

2. Why Google Mock?

Although simulated objects can help you delete unnecessary dependencies during testing and make them fast and reliable, it is difficult to manually use mock in C ++:

  • Someone must implement Mock. This job is usually boring and error-prone. It's no wonder that people are taking a long distance to avoid it.
  • The quality of these manually written Mock is a bit unpredictable. You may see some truly polished ones, but you may also see some rushed intrusions with various temporary restrictions.
  • The knowledge you get from using a simulation is not transferred to the next one.

In contrast, Java and Python programmers have some elaborate simulation frameworks to automatically create mock. Therefore, Mock is a proven and widely used technology in these communities. Having the right tools is definitely different.

Google Mock is designed to help C ++ programmers. It is inspired by jMock and EasyMock, but the C ++ details are taken into account during design. It will be helpful if you have any of the following problems:

  • Your tests are slow because they depend on too many databases or use expensive resources (such as databases ).
  • Your tests are fragile because some of the resources they use are unreliable (such as networks ).
  • You want to test how the Code fails (for example, file checksum errors), but it is not easy to cause.
  • You need to ensure that your module interacts with other modules in the correct way, but it is difficult to observe the interaction; therefore, it is the most embarrassing to resort to observing the side effects at the end of the action.
  • You want to "simulate" Your dependencies, except that they are not simulated; frankly speaking, you are not excited about the handwritten ridicule.

We recommend that you use Google Mock:

A design tool that allows you to try your interface design as soon as possible. More iterations lead to better design!
A test tool used to cut out the out-site dependency of the test and detect the interaction between the module and its collaborators.

3. Getting Started

Google Mock is easy to use! In your C ++ source file, as long as you # include "gtest/gtest. h" and "gmock/gmock. h", you have prepared.

4. A Mock Turtles case

Let's look at an example. Suppose you are developing a graphic program for Drawing Based on the logo api. How will you test it to do the right thing? Okay, you can run it and compare the screen with the golden screen snapshot, but let us admit: such testing runs and is fragile and expensive (if you just upgraded to a shiny new video card with better anti-aliasing? Suddenly you have to update all the gold images .). If all tests are like this, it would be too painful. Fortunately, you learned about dependency injection and know the right thing: instead of directly interacting with the drawing API, You encapsulate the API in an interface (for example, Turtle, compile the interface with code:

class Turtle {  ...  virtual ~Turtle() {}  virtual void PenUp() = 0;  virtual void PenDown() = 0;  virtual void Forward(int distance) = 0;  virtual void Turn(int degrees) = 0;  virtual void GoTo(int x, int y) = 0;  virtual int GetX() const = 0;  virtual int GetY() const = 0;};

(Note: The Turtle destructor must be virtual, just like all classes you intend to inherit-otherwise, when you delete an object through the Basic pointer, the destructor of the derived class will not be called, and you will get corrupted program status, such as memory leakage .)

You can use PenUp () and PenDown () to control whether the turtle motion leaves a trajectory, and use Forward (), Turn (), and GoTo () to control its motion. Finally, GetX () and GetY () Tell you the turtle at the current position.

Your program usually uses the actual implementation of this interface. During the test, you can use a simulated implementation. This allows you to easily check what drawing elements, parameters, and order your program is calling. Testing written in this way is more powerful and easier to read and maintain (the testing intent is expressed in the Code, rather than in some binary images) to run much faster.

5. Compile the simulation class

If you are lucky, the mock you need has been implemented by some good people. However, you find yourself writing a simulated class and relaxing-Google Mock turns this task into an interesting game! (Well, almost .)

1. How to define it

Using the Turtle interface as an example, the following are simple steps to follow:

After the process, you shoshould have something like:

#include "gmock/gmock.h"  // Brings in Google Mock.class MockTurtle : public Turtle { public:  ...  MOCK_METHOD0(PenUp, void());  MOCK_METHOD0(PenDown, void());  MOCK_METHOD1(Forward, void(int distance));  MOCK_METHOD1(Turn, void(int degrees));  MOCK_METHOD2(GoTo, void(int x, int y));  MOCK_CONST_METHOD0(GetX, int());  MOCK_CONST_METHOD0(GetY, int());}; 

You do not need to define these Simulation Methods elsewhere-MOCK_METHOD * Macro will generate the definition for you. That's easy! Once you get the hang of it, you can pump out mock classes faster than your source-control system can handle your check-ins.

Tip: even if this is too much for you, you will find that the gmock_gen.py tool in the scripts/generator/directory of Google Mock (provided by the cppclean project) is very useful. This command line tool requires you to install Python 2.4. You give it a C ++ file and the name of the abstract class it defines. It will print the definition of the simulation class for you. Due to the complexity of the C ++ language, this script may not always work, but it can be very convenient. For more information, see user documentation.

2. Where to put

When you define a mock class, you need to decide where to place its definition. Some people put it in a * _ test. cc. This is good when mock interfaces (such as Foo) are owned by the same person or team. Otherwise, your test may be interrupted when the owner of Foo changes it. (You cannot really expect the Foo maintainer to fix every test using Foo, can you ?)

Therefore, the empirical rule is: If you need to simulate Foo and it is owned by others, define the simulation class in the Foo package (better, in a test sub-package, you can clearly separate the production code and test utility) and put it in mock_foo.h. Then everyone can reference mock_foo.h from their tests. If Foo changes, only one copy of MockFoo needs to be changed, and only tests dependent on the changed method need to be repaired.

Another way: you can introduce a thin FooAdaptor at the top of Foo and introduce the code to this new interface. Because you have FooAdaptor, you can easily absorb Foo changes. Although this is the initial work, carefully selecting the adapter interface makes your code easier to write and more readable, because you can choose FooAdaptor to suit your specific field better than Foo.

6. Use a simulator during testing

Once you have a simulation class, it is easy to use. The typical workflow is:

Here is an example:

#include "path/to/mock-turtle.h"#include "gmock/gmock.h"#include "gtest/gtest.h"using ::testing::AtLeast;                     // #1TEST(PainterTest, CanDrawSomething) {  MockTurtle turtle;                          // #2  EXPECT_CALL(turtle, PenDown())              // #3      .Times(AtLeast(1));  Painter painter(&turtle);                   // #4  EXPECT_TRUE(painter.DrawCircle(0, 0, 10));}                                             // #5int main(int argc, char** argv) {  // The following line must be executed to initialize Google Mock  // (and Google Test) before running the tests.  ::testing::InitGoogleMock(&argc, argv);  return RUN_ALL_TESTS();}

As you may have guessed, this test check PenDown () is called at least once. If the painter object does not call this method, your test will fail and the following message is displayed:

path/to/my_test.cc:119: FailureActual function call count doesn't match this expectation:Actually: never called;Expected: called at least once.

Tip 1: If you run the test from the Emacs buffer, you can press <Enter> on the row number displayed in the error message to directly jump to the expected failure.

Tip 2: If your simulated object has never been deleted, the final verification will not happen. Therefore, when you allocate a mock to the stack, it is a good idea to use the heap leak checker in the test.

Important: Google Mock needs to set the expected value before calling the mock function. Otherwise, the behavior is undefined. In particular, you cannot interlace EXPECT_CALL () and call the mock function.

This means that EXPECT_CALL () should be read as expected that the call will happen in the future, rather than the call has already occurred. Why does Google Mock work like this? Okay. specify in advance to allow Google Mock to report the violation immediately when the context (stack trace, etc.) is still available. This makes debugging easier.

It is true that this test was designed and not done too much. You can easily achieve the same effect without using Google Mock. However, as we will soon reveal, Google simulation allows you to do more mock.

1. Use Google Mock and any testing framework

If you want to use a testing framework other than Google testing (such as CppUnit or CxxTest) as a testing framework, simply change the main () function in the previous section:

int main(int argc, char** argv) {  // The following line causes Google Mock to throw an exception on failure,  // which will be interpreted by your testing framework as a test failure.  ::testing::GTEST_FLAG(throw_on_failure) = true;  ::testing::InitGoogleMock(&argc, argv);  ... whatever your testing framework requires ...}

This method has a catch: it sometimes causes Google Mock to throw an exception from the destructor of a simulated object. For some compilers, this sometimes causes the test program to crash. You can still note that the test failed, but it is not an elegant failure.

A better solution is to use the Google Test event listener API to correctly report Test failure to the Test framework. You need to implement the OnTestPartResult () method of the event listener interface, but it should be direct.

If this proves to be too much work, we recommend that you stick to Google testing, which works seamlessly with Google Mock (in fact, it is technically part of Google Mock ). If you cannot use Google for testing for a reason, please let us know.

VII. Set expectations

The key to successful use of a simulated object is to set correct expectations for it. If you set too strict expectations, your test will fail as a result of unrelated changes. If you set them too loosely, you can pass the error. All you want to do is correct so that your test can capture the errors you want to capture. Google Mock provides you with the necessary method "just right ".

1. General syntax

In Google Mock, we use the EXPECT_CALL () macro to set the expected value of the simulation method. The general syntax is:

EXPECT_CALL(mock_object, method(matchers))    .Times(cardinality)    .WillOnce(action)    .WillRepeatedly(action);

A macro has two parameters: the mock object, the method and its parameters. Note that the two are separated by commas (,) instead of periods (.). (Why use a comma? The answer is, this is a necessary technical reason .)

A macro can be an optional clause to provide more information about the expectation. We will discuss how each clause works in the following chapter.

This syntax is intended to make it possible to read data such as English. For example, you may guess

using ::testing::Return;...EXPECT_CALL(turtle, GetX())    .Times(5)    .WillOnce(Return(100))    .WillOnce(Return(150))    .WillRepeatedly(Return(200));
The GetX () method of the turtle object will be called five times. It will return 100 for the first time, 150 for the second time, and 200 for each time. Some people like to refer to this syntax style as a domain-specific language (DSL ).

Note:Why do we use macros to do this? It has two purposes: first, it makes the expectation easy to recognize (through grep or by human readers), and second, it allows Google Mock to include the expected location of failed source files in the message, make debugging easier. 2. Matchers: What parameters do we expect?

When a mock function accepts parameters, we must specify what parameters we expect. For example:

// Expects the turtle to move forward by 100 units.EXPECT_CALL(turtle, Forward(100));
Sometimes you may not want to be too specific (Remember, talking about testing too stiff, beyond the intent that the specification leads to fragile testing and fuzzy testing, so we encourage you to specify only the necessary -). If you want to check that Forward () will be called, but you are not interested in its actual parameters, write _ as the parameter, which means "everything ":
using ::testing::_;...// Expects the turtle to move forward.EXPECT_CALL(turtle, Forward(_));

_ Is an instance called a matcher. It is like a predicate. We can test whether a parameter is expected. You can use a pair in EXPECT_CALL (), as long as there is a function parameter.

You can find the list of built-in matching in CheatSheet. For example, here is the Ge (greater than or equal to) pair:

1 using ::testing::Ge;...2 EXPECT_CALL(turtle, Forward(Ge(100))); 

This check, turtle will be notified to move forward at least 100 units.

3. cardinality: How many times will it be called?

The first clause specified after EXPECT_CALL () is Times (). We call its parameter a base because it tells the call how many times it should occur. It allows us to repeat an expectation multiple times without actually writing it multiple times. More importantly, a base can be "fuzzy", just like a matcher. This allows the user to accurately express the intent of the test.

An interesting special case is when we say Times (0 ). You may have guessed-this means that the function should not use the given parameters, and Google Mock will report a Google test failure when the function is called (incorrectly.

We have seen an example of AtLeast (n) as a fuzzy base. For a list of built-in baselines that you can use, see CheatSheet.

The Times () clause can be omitted. If you omit Times (), Google Mock will deduce your base number. Rules are easy to remember:

  • If both WillOnce () and WillRepeatedly () are not in EXPECT_CALL (), the base number of the inference is Times (1 ).
  • If there are n WillOnce () but no WillRepeatedly (), where n> = 1, the base is Times (n)
  • If there are n WillOnce () and one WillRepeatedly (), where n> = 0, the base is Times (AtLeast (n )).

Quiz: If a function is called twice but actually called four times, what do you think will happen?

4. Action: What should I do?

Remember, a simulated object does not actually work? As users, we must tell them what to do when a method is called. This is easy in Google Mock.

First, if a simulated function returns a built-in type or pointer, the function has a default action (a void function returns, and a bool function returns false, other functions return 0 ). In addition, in C ++ 11 and later versions, a simulated function with the default constructor type can return the default constructor value. If you do not say anything, this behavior will be used.

Second, if the simulated function does not have a default action, or the default action is not suitable for you, you can use a series of WillOnce () clauses to specify the action to be taken for each expected match, followed by an optional WillRepeatedly (). For example,

using ::testing::Return;...EXPECT_CALL(turtle, GetX())    .WillOnce(Return(100))    .WillOnce(Return(200))    .WillOnce(Return(300));

This indicates turtle. getX () will be called three Times (Google Mock broke this point from the WillOnce () clause we wrote, because we did not explicitly write Times (), and will return 100,200, and 300.

using ::testing::Return;...EXPECT_CALL(turtle, GetY())    .WillOnce(Return(100))    .WillOnce(Return(200))    .WillRepeatedly(Return(300));

Turtle. getY () will be called at least twice (Google Mock knows this, because we have written two WillOnce () clauses and one WillRepeatedly (), without explicit Times ()), the first time 100,200 is returned for the second time, and 300 starts from the third time.

Of course, if you explicitly write a Times (), Google Mock will not try to deduce the cardinality (base) itself. What if the number you specified is greater than the WillOnce () clause? Okay, after all, WillOnce () is used up, and Google Mock will execute the function every time.Default operation(Unless you have WillRepeatedly ().).

In addition to Return (), what can we do in WillOnce? You can use ReturnRef (variable) to return a reference or call a predefined function.

Important: EXPECT_CALL () statement onlyAssessment onceOperation clause, even if the operation may be executed multiple times. Therefore, you must be careful with the side effects. The following may not do what you want:

int n = 100;EXPECT_CALL(turtle, GetX()).Times(4).WillRepeatedly(Return(n++));

Instead of returning 100,101,102 consecutively,... this mock function will always return 100, becauseN ++ is calculated only once. Similarly, when you execute EXPECT_CALL (), Return (new Foo) creates a new Foo object and returns the same pointer each time. If you want to have side effects every time, you need to define a custom action, which we will teach in CookBook.

Time another quiz! What do you think is the following?

using ::testing::Return;...EXPECT_CALL(turtle, GetY()).Times(4).WillOnce(Return(100));

Apparently, turtle. GetY () is expected to be called four times. But if you think it will return 100 every time, think twice! Remember that each time you call a function, a WillOnce () clause is used and default operations are performed. So the correct answer is that turtle. GetY () will return 100 for the first time, but returns 0 from the second time, becauseReturns the default operation of the int function..

5. Use multiple expectations

So far, we have listed only one expected example. More realistically, You need to specify expectations for multiple simulation methods, which may come from multiple simulation objects.

By default, when a simulated method is called, Google Mock definesReverse OrderSearch for expected values and stop the expected values of the activity that matches the parameters (you can think of it as "the new rule overwrites the old one"). If the request cannot accept any call, you will receive an upper limit violation failure. Here is an example:

using ::testing::_;...EXPECT_CALL(turtle, Forward(_));  // #1EXPECT_CALL(turtle, Forward(10))  // #2    .Times(2);

If Forward (10) Is called three times in a row. The third time it will be an error because the final matching expectation (#2) is saturated. However, if the third Forward (10) is replaced by Forward (20), it will be OK, because now #1 will match expectations.

Note: Why does Google Mock search in the reverse order of expectation? This allows you to set the default expectation in the constructor of the simulated object or in the setup phase of the test fixture, then, you can customize the simulation by writing more specific expectations in the test body. Therefore, if you have two expectations for the same method, you want to put one with more specific mappings after the other, or more specific rules will be overwritten by more general rules.

6. Ordered and unordered calls

By default, the call can be matched even if it does not meet earlier expectations. In other words,The call does not need to occur in the desired order..

Sometimes you may want all the expected calls to occur in strict order. In Google Mock, this is easy:

using ::testing::InSequence;...TEST(FooTest, DrawsLineSegment) {  ...  {    InSequence dummy;    EXPECT_CALL(turtle, PenDown());    EXPECT_CALL(turtle, Forward(100));    EXPECT_CALL(turtle, PenUp());  }  Foo();}

By creating an object of the InSequence type, all expectations in its range are put into the sequence and must occur in order. Because we only rely on the constructor and destructor of this object for actual work, its name is really irrelevant.

In this example, we test that Foo () calls three expected functions in the writing order. If the call is out of order, it will be an error.

(If you care about the relative sequence of some calls, but not all calls, can you specify any part of the order? The answer is... Yes! If you are impatient, you can find the details in CookBook .)

7. All expectations are stuck (Sticky) (unless otherwise stated)

Now, let's take a quick test to see how well you can use this simulation. How do you test it? turtle is required to go to the origin twice (you want to ignore any other commands )?

After you give your answers, let's take a look at our comparison notes (solve it yourself first-don't cheat !) :

using ::testing::_;...EXPECT_CALL(turtle, GoTo(_, _))  // #1    .Times(AnyNumber());EXPECT_CALL(turtle, GoTo(0, 0))  // #2    .Times(2);

Assume that turtle. GoTo (0, 0) is called three times. The third time, Google Mock will see the parameter matching expectation #2 (Remember, we always choose the last matching expectation ). Now, because we say there should be only two such calls, Google Mock will immediately report an error. This is basically what we tell you in the "use multiple expectations" section above.

This example shows that Google Mock's expectation isThe default value is "stickiness"Even after we reach the upper bound of the call, they remain active. This is an important rule to remember, because it affects the meaning of a specification and is different from what it does in many other Mock frameworks (Why do we do this? Because we think our rules make common situations easier to express and understand .).

Simple? Let's see if you really understand it: what is the following code?

using ::testing::Return;...for (int i = n; i > 0; i--) {  EXPECT_CALL(turtle, GetX())      .WillOnce(Return(10*i));}

If you think it says, turtle. GetX () will be called n times, and will return 10, 20, 30,..., consecutive, think twice before going! The problem is that, as we said, expectations are sticky. So the second turtle. getX () is called, and the last (latest) EXPECT_CALL () Statement will match, and will immediately cause the error "the upper limit is exceeded (upper bound exceeded)"-this code is not very useful!

A correct statement is that turtle. GetX () will return 10, 20, 30,..., specifically, the expectation is non-stick. In other words, they should retire as soon as possible after saturation:

using ::testing::Return;...for (int i = n; i > 0; i--) {  EXPECT_CALL(turtle, GetX())    .WillOnce(Return(10*i))    .RetiresOnSaturation();}

In addition, there is a better method: in this case, we expect the call to take place in a specific order, and we arrange the actions to match the order. Since order is important here, we should use an order:

using ::testing::InSequence;using ::testing::Return;...{  InSequence s;  for (int i = 1; i <= n; i++) {    EXPECT_CALL(turtle, GetX())        .WillOnce(Return(10*i))        .RetiresOnSaturation();  }}

By the way, the expectation may be non-stick in other cases when it is in a sequence-once the expectation behind the sequence has been used, it automatically retires (and will never be used to match any call ).

8. Bored call

There may be many methods to simulate objects, not all of which are so interesting. For example, in some tests, we may not care how many times GetX () and GetY () are called.

In Google Mock, if you are not interested in a method, just don't say anything. If you call this method, you will see a warning in the test output, but it will not fail.

8. What should I do now?

Congratulations! You have learned enough to use Google Mock. Now, you may want to join the googlemock discussion group and actually use Google Mock to write some tests-this is interesting. Hey, it can even be addictive-you have been warned.

Then, if you want to add your Mock vendor, you should move it to CookBook. You can learn about many advanced features of Google Mock and improve your enjoyment and test happiness.

9. A small example

This is a small example I wrote. It is a simple example:

// Define the class FooInterface {public: virtual ~ FooInterface () {} virtual std: string getArbitraryString () = 0; virtual int getPosition () = 0 ;};

  

// Simulation class MockFoo: public FooInterface {public: MOCK_METHOD0 (getArbitraryString, std: string (); MOCK_METHOD0 (getPosition, int ());};

  

# Include "stdafx. h "using namespace seamless; using namespace std; using: testing: Return; int main (int argc, char ** argv) {// Since Google Mock depends on Google Test, initGoogleMock () is also responsible for initializing Google Test. // Therefore there's no need for calling testing: InitGoogleTest () separately.: testing: InitGoogleMock (& argc, argv); int n = 100; string value = "Hello World! "; MockFoo mockFoo; EXPECT_CALL (mockFoo, getArbitraryString ()). times (1 ). willOnce (Return (value); string returnValue = mockFoo. getArbitraryString (); cout <"Returned Value:" <returnValue <endl; // here, Times (2) indicates two calls, but only one call is called below, therefore, an exception EXPECT_CALL (mockFoo, getPosition () is reported ()). times (2 ). willRepeatedly (Return (n ++); int val = mockFoo. getPosition (); // 100 cout <"Returned Value:" <val <endl; // getPosition indicates two calls. Only one call is called here, return EXIT_SUCCESS ;}

Running result:

We can see that all the above are output, and there is an error at the end. This error is because: getPosition specifies two calls, and only one call is made here, so the running result shows an error.

Reprinted please indicate the source: http://www.cnblogs.com/jycboy/p/gmock_summary.html

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.