Mockito - Feeling I Don't Use Its Full Potential

When using Mockito, I only use it to extract dependencies, i.e. my workflow looks basically like this:

I have a class with dependencies:

public class C { public C (A a, B b) { this.a = a; this.b = b; } public String fooBar() { return a.foo() + b.bar(); } } 

In my test class, I make fun of these dependencies and tell them what values ​​to return when calling some of the specified methods:

 public class CSpec { private A a = mock(A.class); private B b = mock(B.class); @Test public itShouldReturnFooBar() { when(a.foo()).thenReturn("foo"); when(b.bar()).thenReturn("bar"); C c = new C(a, b); assertThat(c.fooBar().isEqualTo("foobar")); } } 

(I hope this example is not too simple or too deduced ;-)). This works great, it allows me to test classes (here: C) in isolation. However, I never use the Mockito verify methods or any of its other functions. Is it normal / sufficient to use Mockito in this way?

+6
source share
5 answers

Verify is usually used to verify that your C actually calls the A.foo () and B.bar () methods. So you can add

 verify(a).foo(); verify(b).foo(); 

before or after assertThat. I don’t think you need or need to use them here, but there are several situations in which you will need the following:

  • a or b does something that is not visible / accessible from the c public API (e.g. logging)
  • Are you concerned about the execution order
  • You want to make sure that only the a.foo and b.bar methods a.foo b.bar , nothing more than a.foo2
  • You can use these mocks as spies, so the call to a.foo will then be redirected to aReal.foo
+5
source

The verify approach verify especially useful in the Tell Do not Ask programming style.

Consider the following version of your C class:

 public class C { public C(A a, B b, CListener L) { ... } ... public void foobar() { String result = complexPrivateMethod(a, b); L.fooBarred(result); } } 

Thus, instead of just calculating the result, you inform the interested parties (for example, the user interface) of the results.

To check foobar now, you want to check if the listener is being called correctly:

 public class CTest { @Mock CListener mockListener; ... @Test itShouldTellCAboutFooBar() { C c = new C(stubbedA, stubbedB, mockedListener); ... verify(mockedListener).fooBarred("foobar"); } } 

This use of verify is typical of test-based development: see Freeman and Pryce The growing object-oriented test-driven software .

Thus, if you want to use the full potential of Mockito (question), you most need to adopt the appropriate design philosophy in your code.

+2
source

Yes, there is no problem with this test, it’s great. The simple fact that stubs are used makes the test work, if you remove or modify the stubs, then the test will not work.

Adding validation statements will simply make things redundant in such tests.

However, if you definitely want to check the arguments, the order or number of interactions, or something else, then you definitely want to add interaction checks between the test object and its employees.

+1
source

It is perfectly normal to use Mockito that way. But if your code becomes more complex, you need to do a few more things to check your code as simple as possible.

Another small example:

 public void eitherAorB() { if(somethingIsTrue) { a.doSomething(); } else { b.doSomethingElse(); } } 

You might want to make sure that the expected method is called on the expected object.

 @Test public doSomethingShouldBeCalledOnA() { A a = mock(A.class); C c = new C(a, new B()); c.setSomeThingIsTrue(true); eitherAorB(); verify(a).doSomething(); } @Test public doSomethingElseShouldBeCalledOnB() { B b = mock(B.class); C c = new C(new A(), b); c.setSomeThingIsTrue(false); eitherAorB(); verify(b).doSomethingElse(); } 

In other cases, you may need to know what parameter was passed to the method. For this you need an ArgumentCaptor.

Or in some cases, you need to call the actual method or use the actual object (without a layout), so it's time to spy on the object, grab the arguments, or test the behavior.

Thus, for Mockito you may need a lot more time.

+1
source

The answers that have been given so far are good, but there are additional features that you did not talk about. Annotations @Mock, @Spy, @InjectMocks very useful. Along with verify(...) methods, there is also an InOrder class for checking the order of method calls. And you may already be using matching methods ( <T> any(T t), anyString() , etc.), but you are not showing that you are using these tools.

+1
source

Source: https://habr.com/ru/post/909064/


All Articles