Tutorial 2 0
History Key
- New content
Removed content
Recent Versions
Choose two versions to compare, or click the link to view it.
1. Basic usage
Say, we have a class called Foo.
class Foo {
private:
IBar *bar;
public:
Foo(IBar *bar);
int a();
};
We want to test the a() function. It uses an object with the interface IBar.
class IBar {
public:
virtual ~IBar() {}
virtual void b() = 0;
virtual int c(std::string) = 0;
};
It is some kind of interface crucial to the function of the a() function in Foo, but we really would rather not use the real Bar objects because:
It is large
It is slow
It is not tested
It uses external stuff (files, databases, network)
It does not exist yet
It is not relevant to Foo's internal logic and to its tests
So, we want to make a test for Foo without using Bar objects. We can use anything instead of Bar that satisfies the IBar interface, so we create a mock repository and tell it to give us a IBar implementing object of otherwise unspecified contents:
void !TestAFunctionInFoo()TestAFunctionInFoo() {
!MockRepositoryMockRepository mocks;
IBar *barMock = mocks.InterfaceMock<IBar>();
Now we have an IBar and we can create the Foo to use it:
Foo *newFoo = new Foo(barMock);
We know that Foo doesn't use its IBar during it's construction. Now, we register the expectations with the mock repository, so it knows what to expect. If we call something we didn't mention before, we get a regular exception informing us of that. If we on the other hand call something we did mention before, it can be checked for validity. We expect a call on b().
mocks.ExpectCall(barMock, &IBar::b);
We also expect a call on c(), with "hello" as argument, upon which it should return 42. Let's inform the mock repository of this information:
mocks.ExpectCall(barMock, &IBar::c).With("hello").Return(42);
That reads a lot like the sentences you just read describing what we were going to do - actually, you can read this out loud as regular text. The mock repository arms all expectations immediately, so we can now execute the test itself and let it call the mock functions.
newFoo->a();
We close up the test case, letting the mock repository clean up all the mocks and related stuff:
delete newFoo;
}
This last line (the accolade) tells the mock repository to verify its expectations. If an error already occurred, it will not throw a second exception.
Notice that in the process of making this test, we don't know Bar at all. Bar might not exist, might be unusable or might be developed on the other side of the planet. We have been able to test our code, without knowing Bar or anything about Bar except that it implements IBar.
This completes the first bit of the tutorial. To make this compile, include and include "hippomocks.h", and it will compile and work on at least GCC and Visual Studio.
2. More complex stuff
We can mock more than just functions with return values, that have to be called, and that always execute in the same order. The basic call:
mocks.ExpectCall(barMock, &IBar::c).With("hello").Return(42);
We can tell the mocking framework a function does not return a value but throws an exception:
mocks.ExpectCall(barMock, &IBar::c).With("hello").Throw(std::exception());
We can tell it that a function may be called, but doesn't have to be called:
mocks.OnCall(barMock, &IBar::c).With("hello").Return(42);
Maybe we don't care about the arguments to a function
mocks.ExpectCall(barMock, &IBar::c).Return(42);
Maybe we want to substitute the entire function body?
int someOtherFunction(std::string);
mocks.ExpectCall(barMock, &IBar::c).With("hello").Do(someOtherFunction);
What if we expect multiple, different calls?
mocks.ExpectCall(barMock, &IBar::c).With("hello").Return(42);
mocks.ExpectCall(barMock, &IBar::c).With("world").Return(42);
And if we don't care about the order?
mocks.autoExpect = false;
mocks.ExpectCall(barMock, &IBar::c).With("hello").Return(42);
mocks.ExpectCall(barMock, &IBar::c).With("world").Return(42);
And what if we do care about the order, but only between certain function calls? (yes, we're going to make this hard)
mocks.autoExpect = false;
Call &callOne = mocks.ExpectCall(barMock, &IBar::c).With("hello").Return(1);
Call &callTwo = mocks.ExpectCall(barMock, &IBar::c).With("world").Return(2);
mocks.ExpectCall(barMock, &IBar::c).After(callOne).With("1").Return(3);
mocks.ExpectCall(barMock, &IBar::c).After(callTwo).With("2").Return(4);
When we have a class that has members, how do we make sure it's constructed?
Bar *barMock = mocks.ClassMock<Bar>();
And when Bar has both pure virtual functions and members?
// there's a limit in the language that disallows us from making a mock of this, as we can't call the constructor and we can't skip calling the constructor
// The only solution at the moment is to derive a class from it that implements the pure virtuals and then to make a mock out of that. The implementation
// will not be used at all, ever, except for calling the constructor.
class !BarImplBarImpl : public Bar {
public:
virtual void b() {}
};
Bar *barMock = mocks.ClassMock<BarImpl>();
If you can think of a use case that is not clear or easy with these constructs, please tell us!
Enjoy!