Is it possible to scope an expectation using Google Mock? In other words, let's say I have the following test fixture:
class Fixture : public testing::Test
{
public:
void SetUp();
void TearDown();
ObjectUnderTest testObject;
MockObject mock;
};
Now, in the SetUp() function, I want to allow a mock function call as many times as is necessary during initialisation:
void Fixture::SetUp()
{
EXPECT_CALL(mock.DoStuff(_)).Times(Any());
testObject.Initialise(mock);
}
After this, I want this particular expectation to go out-of-scope and any calls to DoStuff() to generate a failure. I can't use RetiresOnSaturation() because it will never saturate!
In other words, if I have the following test case:
TEST_F(Fixture, DoesWhatItsSupposedTo)
{
EXPECT_CALL(mock, DoStuff(Eq(3)));
testObject.DoSomething(mock);
}
I would like this to fail if DoSomething() calls DoStuff(4) on the mock object. With gmock default behaviour (which is right for most scenarios), it will first check the second expectation that won't match; it will then check the expectation in SetUp() that will match and pass.
Does anyone know if this is possible?
It may not be really answer to your question, but you can explicitly forbid a call using .Times(0):
TEST_F(Fixture, DoesWhatItsSupposedTo)
{
EXPECT_CALL(mock, DoStuff(Eq(3)));
EXPECT_CALL(mock, DoStuff(Ne(3)))
.Times(0);
testObject.DoSomething(mock);
}
This will expect one call of DoStuff(3)and no other calls of DoStuff() within this test - any call is first checked against DoStuff(Ne(3)). Before the test, any call will still be accepted.
Related
In this example bellow I will obtain the following behavior:
EXPECT_CALL(barMock, doBar(7))...
Expected arg #0: is equal to 7
Actual: 5
Expected: to be called once
Actual: called once - saturated and active
#include <gmock/gmock.h>
#include <gtest/gtest.h>
class IBar
{
public:
virtual bool doBar(int barParam) = 0;
};
class BarMock : public IBar
{
public:
MOCK_METHOD1(doBar, bool(int));
};
class Foo
{
public:
Foo(IBar& bar_)
: bar{ &bar_ }
{
}
void doFoo()
{
bar->doBar(7);
bar->doBar(5);
}
IBar* bar;
};
class FooBarTest : public ::testing::Test
{
public:
void SetUp() override
{
ON_CALL(barMock, doBar(testing::_)).WillByDefault(testing::Return(true));
}
testing::NiceMock<BarMock> barMock;
};
TEST_F(FooBarTest, OnCallExpectCallSameMethod)
{
Foo foo(barMock);
ON_CALL(barMock, doBar(5)).WillByDefault(testing::Return(true));
EXPECT_CALL(barMock, doBar(7)).WillOnce(testing::Return(true));
foo.doFoo();
}
Google test versions tested:
1.8.0
1.8.1
Is this intended to cause an error?
How does google test sets the
order calls? Does EXPECT_CALL has higher priority only in this
scenario?
Yes, it is intended to be an error. One of the GoogleMock policies is that in case of possible ambiguity it's better to throw an error an make user state his intention explicitly.
Adding EXPECT_CALL macro effectively says "I care about calls of this method". Whenever EXPECT_CALL is set, GoogleMock will try to match every EXPECT_CALL it has seen in reverse order of declaration (so the latest defined expects are matched first).
One of the reasons for this design is to allow overriding less specific expects with more specific ones (e.g. in constructor of test fixture you set less restrictive expects, but for certain tests you want to match more precisely). Documentation.
However, there is a way of "ignoring" already fulfilled expectations by adding .RetiresOnSaturation()
TEST_F(FooBarTest, OnCallExpectCallSameMethod)
{
Foo foo(barMock);
ON_CALL(barMock, doBar(5)).WillByDefault(testing::Return(true));
EXPECT_CALL(barMock, doBar(7))
.WillOnce(testing::Return(true))
.RetiresOnSaturation();
foo.doFoo();
}
RetiresOnSaturation() will make expectations retired after it has been saturated (i.e. called as many time as expected). GoogleMock will skip over retired expectations as long as there are still any non-retired ones (if all of them are retired then it still prints an error).
If you however need to accept calls doBar(5) before doBar(7), then the only way to do so is to define it as expectation as well:
TEST_F(FooBarTest, OnCallExpectCallSameMethod)
{
Foo foo(barMock);
EXPECT_CALL(barMock, doBar(5)).WillRepeatedly(testing::Return(true));
EXPECT_CALL(barMock, doBar(7))
.WillOnce(testing::Return(true))
.RetiresOnSaturation();
foo.doFoo();
}
RetiresOnSaturation() is still needed because of LIFO (last in, first out) processing of expectations.
Suppose, I have a test class with two methods as follows:
public class TestClass {
#Mock
TestClass testObject;
#Test
public void method1() {
doReturn("str").when(testObject).method2();
String s1 = testObject.method2(); // This line gives compilation
//error. Type mismatch cannot convert from void to string
}
#Test
public void method2() {
}
I am basically trying to mock method2 which is a dependency in method1.
But as you can see, the method2 return type is void. So, I am using doReturn to mock it.
As far as my understanding goes, although the method2 's return type is void, after I mock it, the mocked version of method2 should return String type.
But, as I have commented in method1, it is giving type mismatch.
You are simply getting mocking wrong.
Mocking means: instead of create "real" objects of a specific class, you create a stub/dummy/mock that looks like an object of that class. But in reality - it is not.
Beyond that: mocking can not change the signature of a method. So your idea that you could somehow use mocking to have a void method return something is wrong.
You are simply going down the wrong rabbit hole - what you intend to is not possible.
I think you're using the wrong method. doReturn allows you to "inject" the result of the execution. If you want to "falsify" the whole method execution you should consider using doAnswer:
doAnswer(new Answer<Void>() {
public Void answer(InvocationOnMock invocation) {
// whatever you want to execute here...
// Simply return null
return null;
}
}).when(testObject).method2();
I recently saw some Mockito 1.9.5 code that worked like this:
MyObject myObject = new MyObject();
...
Mockito.when(myObject.someMethod()).thenReturn("bogus");
Since myObject is not a mock object, but is an instance of a non-mocked class, I was surprised this compiled and ran without failing the unit test. I expected I would get a failure saying something like "You asked me to set up an expectation on a non-mock object, and I expected to set expectations only on mock objects."
Why doesn't this code cause a test failure?
Update: adding more code that is necessary to actually replicate the behavior I find confusing. These examples fully illustrate my question. The following code behaves as I expected--when I run this test the test fails with a message that
when() requires an argument which has to be 'a method call on a mock'.
public class AnotherObject{
public String doSomething(){
return "did something";
};
}
public class MyObject{
private AnotherObject anotherObject = new AnotherObject();
public void setAnotherObject(AnotherObject anotherObject) {
this.anotherObject = anotherObject;
}
public String someMethod(){
return anotherObject.doSomething();
}
}
#Test
public void WhyDoesWhenWorkOnNonMock() throws Exception {
MyObject myObject = new MyObject();
Mockito.when(myObject.someMethod()).thenReturn("bogus");
}
Now if I add a couple specific lines to this contrived test, the test no longer fails even though I expected the same failure and same message as before:
public class AnotherObject{
public String doSomething(){
return "did something";
};
}
public class MyObject{
private AnotherObject anotherObject = new AnotherObject();
public void setAnotherObject(AnotherObject anotherObject) {
this.anotherObject = anotherObject;
}
public String someMethod(){
return anotherObject.doSomething();
}
}
#Test
public void WhyDoesWhenWorkOnNonMock() throws Exception {
MyObject myObject = new MyObject();
AnotherObject mockAnotherObject = Mockito.mock(AnotherObject.class);
myObject.setAnotherObject(mockAnotherObject);
Mockito.when(myObject.someMethod()).thenReturn("bogus");
}
By incredible and fragile coincidence, probably, unless myObject was actually set to be a spy.
Mockito allows for the creation of a "spy" of a real object:
MyObject myObject = spy(new MyObject());
Mockito.when(myObject.someMethod()).thenReturn("something");
// myObject is actually a duplicate of myObject, where all the fields are copied
// and the methods overridden. By default, Mockito silently records interactions.
myObject.foo(1);
verify(myObject).foo(anyInt());
// You can stub in a similar way, though doReturn is preferred over thenReturn
// to avoid calling the actual method in question.
doReturn(42).when(myObject).bar();
assertEquals(42, myObject.bar());
Barring that, this code is probably not working the way it looks like it should. when's parameter is meaningless, and is sugar meant to hide that the mocked interaction is the most recent method call to a mock. For example:
SomeObject thisIsAMock = mock(SomeObject.class);
OtherObject notAMock = new OtherObject();
thisIsAMock.methodOne();
Mockito.when(notAMock.someOtherMethod()).thenReturn("bar");
// Because notAMock isn't a mock, Mockito can't see it, so the stubbed interaction
// is the call to methodOne above. Now methodOne will try to return "bar",
// even if it isn't supposed to return a String at all!
Mismatches like this can be easy sources of ClassCastException, InvalidUseOfMatchersException, and other bizarre errors. It's also possible that your real MyObject class takes a mock as a parameter, and that last interaction is with a mock that someMethod interacts with.
Your edit confirms my suspicions. As far as Java is concerned, it needs to evaluate the parameter to when before it can invoke when, so your test calls someMethod (real). Mockito can't see that—it can only take action when you interact with one of its mocks—so in your first example it sees zero interactions with mocks and thus it fails. In your second example your someMethod calls doSomething, which Mockito can see, so it returns the default value (null) and marks that as the most recent method call. Then the call to when(null) happens, Mockito ignores the parameter (null) and refers to the most recently called method (doSomething), and stubs that to return "bogus" from that point on.
You can see that by adding this assertion to your test, even though you never stubbed it explicitly:
assertEquals("bogus", mockAnotherObject.doSomething());
For an additional reference, I wrote a separate SO answer on Mockito matchers, for which the implementation details might be useful. See steps 5 and 6 for an expanded view of a similar problem.
I discovered that stub and mock are very helpful in testing.
But I wondering about one thing. I think an example will show it clearly.
Class A {
public function isOk() {
// some work
}
public function iAmDepend() {
if ($this->isOk()) {
// do work
}
}
}
class TestA {
public function testIsOk() {
// Test itOk here
}
public function testIAmDepend() {
mock(A)->method(isOk)->return(true);
// tests for iAmDepend
}
}
It wise to do something like this? Stub method of tested class. Or maybe it breaks some rules?
PS. I can't refactore code
Your examples are correct, i.e. testIsOk tests only IsOk, and testIAmDepend only IAmDepend.
But there is important difference between mock and stub that you have to understand: difference between mock and stub.
In your example, if testIAmDepend is verifying that isOk has been called with some arguments and this is part of your assertion for unittest, this is mock. Otherwise this is stub, and you aren't going to verify that it has been called or not.
What is the difference between using andReturn(T value) vs andStubReturn(T value) for EasyMock?
In what situation would you use andStubReturn() where andReturn() can't achieve the same result?
You use a stub return for a method call on the mock that you expect to happen but aren't otherwise interested in. You use a regular return for a "regular" method call.
Consider the following method:
public void someMethod(String arg) {
if (logger.isDebugEnabled()) {
logger.debug("Calling doSomething() on service "
+ service.getName().hashCode());
}
service.postMessage("{" + arg + "}");
if (logger.isDebugEnabled()) {
logger.info("Finished calling doSomething() on service "
+ service.getName().hashCode());
}
}
...where service is a mockable field. The hashCode() thing in the log statements is contrived, but the point is that your mock needs to respond to any number of calls to getName() to avoid an NPE, while you couldn't otherwise care less about it.
When writing an EasyMock based unit test for this method, you'd andStubReturn() the call to getName() and use a normal andReturn() for the call to postMessage(String). When you verify the mock object, it'll only consider the latter and your the test doesn't break if you change the log4j config.
An additional note for clarity.
If you use .andStubReturn() (or if you use .andReturn(foo).anyTimes()), there will be no minimum expected call count. So if you set a mock expectation using either of these two, and the mocked method is NOT called, the .verify() call will not assert.
Example that will NOT assert when the mocked method isn't called;
FooClass myFooClass = EasyMock.createNiceMock(FooClass.class);
EasyMock.expect(myFooClass.someMethod(EasyMock.anyInt()).andStubReturn(true);
EasyMock.replay(myFooClass);
EasyMock.verify(myFooClass);
Example that WILL assert when the mocked method isn't called;
FooClass myFooClass = EasyMock.createNiceMock(FooClass.class);
EasyMock.expect(myFooClass.someMethod(EasyMock.anyInt()).andReturn(true).atLeastOnce();
EasyMock.replay(myFooClass);
EasyMock.verify(myFooClass);