Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using Mockito to stub and execute methods for testing

I've asked a couple of jUnit and Mockito oriented questions recently and I'm still really struggling to get the hang of it. The tutorials are all for very simple examples, so I'm struggling to scale up my test cases to work for my classes.

I'm currently trying to write some test cases for a method I have in one of my agents in a webapp. The method interacts with a couple of other methods inside the agent to validate some objects. I just want to test this one method right now.

Here's what I have tried to do:

  1. Create a Mockito object of my agent like so:

    MyProcessingAgent mockMyAgent = Mockito.mock(MyProcessingAgent.class);

  2. Setup stubs(hopefully the right term) using Mockito.when like so:

    Mockito.when(mockMyAgent.otherMethod(Mockito.any(arg1)).thenReturn(requiredReturnArg);

  3. Try executing my method like so:

    List myReturnValue = mockMyAgent.methodThatNeedsTestCase();

I was expecting to things in myReturnValue, but received 0 instead so I tried to debug. When I call the method, it never executes. I have a debug point at the first line in the method that never gets touched.

If I want to execute the code in one method of a class, but force other methods in the class (one's that try to interact with databases in the outside world) to return faked out values. Is this possible with Mockito?

It appears that my current method of approach is not a correct testing style, but I'm not sure how to move forward. Can I mock my class and have one method be executed like normal while other methods are stubbed to return my given values so that I don't have to deal with data access during testing this one method?

like image 346
Kyle Avatar asked Apr 12 '13 16:04

Kyle


People also ask

What is Mockito stub method?

A stub is a fake class that comes with preprogrammed return values. It's injected into the class under test to give you absolute control over what's being tested as input. A typical stub is a database connection that allows you to mimic any scenario without having a real database.

What is stub and mock in testing?

Stub: a dummy piece of code that lets the test run, but you don't care what happens to it. Substitutes for real working code. Mock: a dummy piece of code that you verify is called correctly as part of the test. Substitutes for real working code.

How do you mock another method that is being tested in the same class?

We can mock runInGround(String location) method inside the PersonTest class as shown below. Instead of using mock(class) here we need to use Mockito. spy() to mock the same class we are testing. Then we can mock the method we want as follows.


2 Answers

You are confusing a Mock with a Spy.

In a mock all methods are stubbed and return "smart return types". This means that calling any method on a mocked class will do nothing unless you specify behaviour.

In a spy the original functionality of the class is still there but you can validate method invocations in a spy and also override method behaviour.

What you want is

MyProcessingAgent mockMyAgent = Mockito.spy(MyProcessingAgent.class); 

A quick example:

static class TestClass {      public String getThing() {         return "Thing";     }      public String getOtherThing() {         return getThing();     } }  public static void main(String[] args) {     final TestClass testClass = Mockito.spy(new TestClass());     Mockito.when(testClass.getThing()).thenReturn("Some Other thing");     System.out.println(testClass.getOtherThing()); } 

Output is:

Some Other thing 

NB: You should really try to mock the dependencies for the class being tested not the class itself.

like image 182
Boris the Spider Avatar answered Oct 10 '22 23:10

Boris the Spider


So, the idea of mocking the class under test is anathima to testing practice. You should NOT do this. Because you have done so, your test is entering Mockito's mocking classes not your class under test.

Spying will also not work because this only provides a wrapper / proxy around the spied class. Once execution is inside the class it will not go through the proxy and therefore not hit the spy. UPDATE: although I believe this to be true of Spring proxies it appears to not be true of Mockito spies. I set up a scenario where method m1() calls m2(). I spy the object and stub m2() to doNothing. When I invoke m1() in my test, m2() of the class is not reached. Mockito invokes the stub. So using a spy to accomplish what is being asked is possible. However, I would reiterate that I would consider it bad practice (IMHO).

You should mock all the classes on which the class under test depends. This will allow you to control the behavior of the methods invoked by the method under test in that you control the class that those methods invoke.

If your class creates instances of other classes, consider using factories.

like image 23
John B Avatar answered Oct 11 '22 01:10

John B