Why does Mockito "when" work on a non-mock object? - unit-testing

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.

Related

Understanding how to do JUnit testing with Mockito doReturn/when for the methods with return type void

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();

Testing that one class method calls another

Imagine I have the following class.
class SomeClass {
public function shortcutMethod($arg1) {
return $this->method($arg1, 'something');
}
public function method($arg1, $arg2) {
// some stuff
}
}
So the shortcutMethod is a shortcut to the other method. Let us say I want to write a test that given and $arg1 the shortcutMethod will correctly call method with the correct arguments.
So far I think I figured I need to mock the class to expect a call to method with some arguments and then call shortcutMethod on the mock object like so (note I am using Mockery).
$mock = m::mock("SomeClass");
$mock = $mock->shouldReceive('method')->times(1)->withArgs([
'foo',
'something'
]);
$mock->shortcutMethod('foo');
This results in an exception like so shortcutMethod() does not exist on this mock object.
Did I misunderstand the usage for mocking? I understand it makes more sense for objects that are dependency injected into the class, but what in this scenario? How would you go about it? And perhabs more importantly, is this sort of testing useless, and if so, why?
You should use mocking to mock out the dependencies of the class under test, not the class under test itself. After all, you are trying to test the real behavior of your class.
Your example is a little basic. How you would test such a class would depend on what your method function does. If it returns a value that is in turn returned by shortCutMethod then I would say that your should just be asserting the output of shortCutMethod. Any dependencies within the method function should be mocked (methods belonging to other classes). I'm not that familiar with mockery, but I've given a tweaked version of your example a go.
class SomeClass {
private $dependency;
public function __construct($mockedObject) {
$this->dependency = $mockedObject;
}
public function shortcutMethod($arg1) {
return $this->method($arg1, 'something');
}
public function method($arg1, $arg2) {
return $this->dependency->mockedMethod($arg1, $arg2);
}
}
$mock = m::mock("mockedClass");
$mock->shouldReceive('mockedMethod')->times(1)->withArgs([
'foo',
'something'
])->andReturn('returnedValue');
$testCase = new SomeClass($mock);
$this->assertEquals(
'returnedValue',
$testCase->shortcutMethod('foo')
);
Having said that, it is possible to partially mock your class under test so that you can test the real behavior of the shortCutMethod function but mock out the method function to assert that it is called with the expected arguments. Have a look at partial mocks.
http://docs.mockery.io/en/latest/reference/partial_mocks.html

Add constant to a mock in PHPUnit

Is it possible to add a class constant to a mock using PHPUnit?
Here an example:
class SomeTest extends PHPUnit_Framework_TestCase {
public function setUp() {
$mock = $this->getMock( 'SomeClass' );
// Here I'd like to add a constant to $mock; something like
// $mock::FOOBAR;
}
}
Does any of you know how can I get this behavious to work?
Thx!
This question has been around a while with no answers, but I ran into this same problem. This does not appear to be possible; however, there's at least one dirty work-around:
In your test file
<?php
class SomeClass {
const FOOBAR = 'foobar';
}
class SomeTest extends PHPUnit_Framework_TestCase {
public function setUp() {
$mock = $this->getMock( 'SomeClass' );
}
}
// tests
?>
Then, you use your mocked object for mocked functionality, and you use the class constant the same way you would have originally. For example:
// Call a method on mocked object
// (would need to add this method to your mock, of course)
$mock->doSomething();
// Use the constant
$fooBar = SomeClass::FOOBAR;
This is dirty, so I'm sure things could get pretty messed up if you're using some sort of autoloading that tries to load the actual SomeClass class, but this will work "fine" if you're not loading the original SomeClass.
I'm definitely interested to hear other solutions as well as get some feedback on just how dirty this really is.

How to use thenAnswer with method which returns void

I want to unit test following method
public void addRecord(Record record)
{
Myclass newObj = new Mycalss();
// It creates newObj object, set some values using record object.
// and it adds the newObj in daatbase.
dataReqDao.persist(newObj);
}
I have mocked dataReqDao.persist method but how can I verify if right values are copied into newObj object? I want to get the newObj object.
I think thenAnswer will be the appropraite method to retrieve newObj ie method arguments but dont know how to use it method which returns void.
Update:
I tried
doAnswer(new Answer<Myclass>() {
public Myclass answer(InvocationOnMock invocation) {
Object[] args = invocation.getArguments();
return (Myclass)args[0];
}
}).when(dataReqDao.persist(any(Myclass.class)));
EDIT:
It should be (Thanks David)
doAnswer(new Answer<Myclass>() {
public Myclass answer(InvocationOnMock invocation) {
Object[] args = invocation.getArguments();
return (Myclass)args[0];
}
}).when(dataReqDao).persist(any(Myclass.class));
You can create a custom argument matcher that would check fields of that object, or use an argument captor to capture the object for further inspection.
For example, as follows:
ArgumentCaptor<Myclass> c = ArgumentCaptor.forClass(Myclass.class);
verify(dateReqDao).persist(c.capture());
Myclass newObj = c.getValue();
... // Validate newObj
You need to make it with thenAnswer (or then which i personally prefer), so you can assert/verify the values at the time of method call, in the method.
when(dataReqDao.persist(newObj)).then(new Answer<Void>() {
#Override
public Void answer(final InvocationOnMock invocation) {
Myclass newObjActual = (Myclass) invocation.getArguments()[0];
// Control
assertEquals(..., newObjActual.getX());
assertEquals(..., newObjActual.getY());
return null;
}
});
// Run Test
x.addRecord(record);
Here is a detail explanation: https://akcasoy.wordpress.com/2015/04/09/the-power-of-thenanswer/ (Use case 2)
ArgumentCaptor does not test in a clever way. When you change your method like this:
public void addRecord(Record record)
{
Myclass newObj = new Mycalss();
dataReqDao.persist(newObj);
// first persist, than set attributes
newObj.setX(..);
}
.. your test with Captor still runs, but it should fail. Since the ArgumentCaptor does not capture that state of the object at the time of call, but just the objectId, it does not matter for captor whether you set your attributes before or after dao call. Yet a good test should fail with every functional change. Here is my article exactly about this case:
https://akcasoy.wordpress.com/2015/02/03/how-to-ensure-quality-of-junit-tests/ (the above stubbing with the then is a better approach though than the one with InOrder approach)
Myclass newObj = new Myclass();
That line troubles me. If you are using dependency injection, you should have your factory send you an instance of that object. Then, when you create your unit tests, you can have the test factory send in a mock instance of MyClass which the unit test can also have access to. Then you can use axtavt's captor to see if it really did what it was supposed to do. There's nothing wrong with the unit test the way you did it, it's just that any() is kind of weak given that you know it is passing in an object of that type--what you want to know in the test is whether the object is the one you intended and has not been modified.

How to use Rhino Mock to mock a local function calling?

Here is my situation:
I want to test on the "HasSomething()" function, which is in the following class:
public class Something
{
private object _thing;
public virtual bool HasSomething()
{
if (HasSomething(_thing))
return true;
return false;
}
public virtual bool HasSomething(object thing)
{
....some algo here to check on the object...
return true;
}
}
So, i write my test to be like this:
public void HasSomethingTest1()
{
MockRepository mocks = new MockRepository();
Something target = mocks.DynamicMock(typeof(Something)) as Something;
Expect.Call(target.HasSomething(new Object())).IgnoreArguments().Return(true);
bool expected = true;
bool actual;
actual = target.HasSomething();
Assert.AreEqual(expected, actual);
}
Is my test written correctly?
Please help me as i can't even get the result as expected. the "HasSomething(object)" just can't be mock in that way. it did not return me 'true' as being set in expectation.
Thanks.
In response to OP's 'answer': Your main problem is that RhinoMocks does not mock members of classes - instead it creates mock classes and we can then set expectations and canned responses for its members (i.e. Properties and Functions). If you attempt to test a member function of a mock/stub class, you run the risk of testing the mocking framework rather than your implementation.
For the particular scenario of the logical path being dependent on the return value of a local (usually private) function, you really need an external dependency (another object) which would affect the return value that you require from that local function. For your code snippet above, I would write the test as follows:
[Test]
public void TestHasSomething()
{
// here I am assuming that _thing is being injected in via the constructor
// you could also do it via a property setter or a function
var sut = new Something(new object());
Assert.IsTrue(sut.HasSomething);
}
i.e. no mocking required.
This is one point of misunderstanding that I often had in the past with regards to mocking; we mock the behaviour of a dependency of the system under test (SUT). Something like: the SUT calls several methods of the dependency and the mocking process provides canned responses (rather than going to the database, etc) to guide the way the logic flows.
A simple example would be as follows (note that I have used RhinoMocks AAA syntax for this test. As an aside, I notice that the syntax that you are using in your code sample is using the Record-Replay paradigm, except that it isn't using Record and Replay! That would probably cause problems as well):
public class SUT
{
Dependency _depend
public SUT (Dependency depend)
{
_depend = depend;
}
...
public int MethodUnderTest()
{
if (_depend.IsReady)
return 1;
else
return -1;
}
}
...
[Test]
public void TestSUT_MethodUnderTest()
{
var dependency = MockRepository.GenerateMock<Dependency>();
dependency.Stub(d => d.IsReady).Return(true);
var sut = new SUT(dependency);
Assert.AreEqual(1, sut.MethodUnderTest());
}
And so the problem that you have is that you are attempting to test the behaviour of a mocked object. Which means that you aren't actually testing your class at all!
In a case like this, your test double should be a derived version of class Something. Then you override the method HasSomething(object) and ensure that HasSomething() calls your one.
If I understand correctly, you are actually interested in testing the method HasDynamicFlow (not depicted in your example above) without concerning yourself with the algorithm for HasSomething.
Preet is right in that you could simply subclass Something and override the behavior of HasSomething to short-circuit the algorithm, but that would require creating some additional test-dummy code which Rhino is efficient at eliminating.
Consider using a Partial Mock Stub instead of a Dynamic Mock. A stub is less strict and is ideal for working with Properties. Methods however require some extra effort.
[Test]
public void CanStubMethod()
{
Foo foo = MockRepository.GenerateStub<Foo>();
foo.Expect(f => f.HasDynamicFlow()).CallOriginalMethod(OriginalCallOptions.NoExpectation);
foo.Expect(f => f.HasSomething()).CallOriginalMethod(OriginalCallOptions.NoExpectation);
foo.Expect(f => f.HasSomething(null)).IgnoreArguments().Return(true);
Assert.IsTrue(foo.HasDynamicFlow());
}
EDIT: added code example and switched Partial Mock to Stub