Given a Foo class written like this:
public class Foo {
private BarFactory barFactory;
public Foo(BarFactory factory) {
this.barFactory = factory;
}
public void foo() {
Bar bar = this.barFactory.createBar();
bar.someMethod();
}
}
in your test method you can inject a BarFactory like this:
@Test
public void testDoFoo() {
Bar bar = mock(Bar.class);
BarFactory myFactory = new BarFactory() {
public Bar createBar() {
return bar;
}
};
Foo foo = new Foo(myFactory);
foo.foo();
verify(bar, times(1)).someMethod();
}
If you don't want to use DI or Factories. You can refactor your class in a little tricky way:
public class Foo {
private Bar bar;
public void foo(Bar bar) {
this.bar = (bar != null) ? bar : new Bar();
bar.someMethod();
this.bar = null; // for simulating local scope
}
}
And your test class:
@RunWith(MockitoJUnitRunner.class)
public class FooTest {
@Mock Bar barMock;
Foo foo;
@Test
public void testFoo() {
foo = new Foo();
foo.foo(barMock);
verify(barMock, times(1)).someMethod();
}
}
Then the class that is calling your foo method will do it like this:
public class thirdClass {
public void someOtherMethod() {
Foo myFoo = new Foo();
myFoo.foo(null);
}
}
Classes:
public class Foo {
private Bar bar = new Bar();
public void foo() {
bar.someMethod();
}
}
public class Bar {
public void someMethod() {
//something
}
}
Test:
@RunWith(MockitoJUnitRunner.class)
public class FooTest {
@Mock
Bar bar;
@InjectMocks
Foo foo;
@Test
public void FooTest() {
doNothing().when(bar).someMethod();
foo.foo();
verify(bar, times(1)).someMethod();
}
}
FooTest.java
package foo;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
//Both @PrepareForTest and @RunWith are needed for `whenNew` to work
@RunWith(PowerMockRunner.class)
@PrepareForTest({
Foo.class
})
public class FooTest {
// Class Under Test
Foo cut;
@Mock
Bar barMock;
@Before
public void setUp() throws Exception {
cut = new Foo();
}
@After
public void tearDown() {
cut = null;
}
@Test
public void testFoo() throws Exception {
// Setup
PowerMockito.whenNew(Bar.class).withNoArguments()
.thenReturn(this.barMock);
// Test
cut.foo();
// Validations
Mockito.verify(this.barMock, Mockito.times(1)).someMethod();
}
}
One way of achieving this without adding in more dependencies or similar is pretty low tech, but it works:
@Test
public void testSomeMethodIsCalledOnce() throws Exception {
final AtomicInteger counter = new AtomicInteger(0);
Mockito.when(someObject.theMethodIWant(anyString()))
.then((Answer<ReturnValue>) __ -> {
teller.incrementAndGet();
return theExpectedAnswer;
});
theObjectUnderTest.theMethod(someTestValue);
assertEquals(1, teller.get());
}
To check if a method was called on a mocked object you can use the Mockito.verify method:,In this example, we assert that the method bla was called on the someMock mock object.,If you would like to check that a method was not called, you can pass an additional VerificationMode parameter to verify:,This also works if you would like to check that this method was called more than once (in this case we check that the method bla was called 23 times):
To check if a method was called on a mocked object you can use the Mockito.verify
method:
Mockito.verify(someMock).bla();
You can also check if a method was called with certain parameters:
Mockito.verify(someMock).bla("param 1");
If you would like to check that a method was not called, you can pass an additional VerificationMode
parameter to verify
:
Mockito.verify(someMock, Mockito.times(0)).bla();
These are more examples for the VerificationMode
parameter, providing more control over the number of times a method should be called:
Mockito.verify(someMock, Mockito.never()).bla(); // same as Mockito.times(0)
Mockito.verify(someMock, Mockito.atLeast(3)).bla(); // min 3 calls
Mockito.verify(someMock, Mockito.atLeastOnce()).bla(); // same as Mockito.atLeast(1)
Mockito.verify(someMock, Mockito.atMost(3)).bla(); // max 3 calls
With Mockito, you create a mock, tell Mockito what to do when specific methods are called on it, and then use the mock instance in your test instead of the real thing. After the test, you can query the mock to see what specific methods were called or check the side effects in the form of changed state.,A mock can be configured to call an invocation listener every time a method of the mock was called. Inside the listener, you can find out whether the invocation produced a value or if an exception was thrown.,Fresh, unaltered mocks are useful only in rare cases. Usually, we want to configure the mock and define what to do when specific methods of the mock are called. This is called stubbing.,If you create a mock of an interface and try to configure a stub to call a real method, Mockito will throw an exception with very informative message. Consider the following snippet:
Getting Mockito is easy these days. If you’re using Gradle, it’s a matter of adding this single line to your build script:
testCompile "org.mockito:mockito−core:2.7.7"
As for those like me who still prefer Maven, just add Mockito to your dependencies like so:
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>2.7.7</version>
<scope>test</scope>
</dependency>
UserRepository
public interface UserRepository {
User findById(String id);
}
PasswordEncoder
public interface PasswordEncoder {
String encode(String password);
}
UserService
public class UserService {
private final UserRepository userRepository;
private final PasswordEncoder passwordEncoder;
public UserService(UserRepository userRepository, PasswordEncoder passwordEncoder) {
this.userRepository = userRepository;
this.passwordEncoder = passwordEncoder;
}
public boolean isValidUser(String id, String password) {
User user = userRepository.findById(id);
return isEnabledUser(user) && isValidPassword(user, password);
}
private boolean isEnabledUser(User user) {
return user != null && user.isEnabled();
}
private boolean isValidPassword(User user, String password) {
String encodedPassword = passwordEncoder.encode(password);
return encodedPassword.equals(user.getPasswordHash());
}
}
The assert passes if the mock has ever been called, unlike assert_called_with() and assert_called_once_with() that only pass if the call is the most recent one, and in the case of assert_called_once_with() it must also be the only call.,This applies to assert_called_with(), assert_called_once_with(), assert_has_calls() and assert_any_call(). When Autospeccing, it will also apply to method calls on the mock object.,First the problem specific to Mock. Mock has two assert methods that are extremely handy: assert_called_with() and assert_called_once_with().,To ignore certain arguments you can pass in objects that compare equal to everything. Calls to assert_called_with() and assert_called_once_with() will then succeed no matter what was passed in.
>>> from unittest.mock
import MagicMock
>>>
thing = ProductionClass() >>>
thing.method = MagicMock(return_value = 3) >>>
thing.method(3, 4, 5, key = 'value')
3
>>>
thing.method.assert_called_with(3, 4, 5, key = 'value')
>>> mock = Mock(side_effect = KeyError('foo')) >>>
mock()
Traceback(most recent call last):
...
KeyError: 'foo'
>>> values = {
'a': 1,
'b': 2,
'c': 3
} >>>
def side_effect(arg):
...
return values[arg]
...
>>>
mock.side_effect = side_effect >>>
mock('a'), mock('b'), mock('c')
(1, 2, 3) >>>
mock.side_effect = [5, 4, 3, 2, 1] >>>
mock(), mock(), mock()
(5, 4, 3)
>>> from unittest.mock
import patch
>>>
@patch('module.ClassName2')
...@patch('module.ClassName1')
...def test(MockClass1, MockClass2):
...module.ClassName1()
...module.ClassName2()
...assert MockClass1 is module.ClassName1
...assert MockClass2 is module.ClassName2
...assert MockClass1.called
...assert MockClass2.called
...
>>>
test()
>>> with patch.object(ProductionClass, 'method', return_value = None) as mock_method:
...thing = ProductionClass()
...thing.method(1, 2, 3)
...
>>>
mock_method.assert_called_once_with(1, 2, 3)
>>> foo = {
'key': 'value'
} >>>
original = foo.copy() >>>
with patch.dict(foo, {
'newkey': 'newvalue'
}, clear = True):
...assert foo == {
'newkey': 'newvalue'
}
...
>>>
assert foo == original
When using mocked dependencies, you usually want to test that your code calls the correct functions. In MockK, this is accomplished using the verify function.,In the previous simple example, verification isn’t very helpful as it just checks that the previous line ran. Verification becomes more useful when you are testing other classes, that depend on mocked instances. Let’s start testing a button.,Using verify to verify that a function was called looks a lot like using every for stubbing. A simple example is to call a method and immediately check that it was called.,A test for the above NavigationView class should check that clicking the goToParkButton tells the navigator to go to the park. If the navigator doesn’t record where it goes, then it can be difficult to check that the button does its job correctly. This is a scenario where MockK can shine.
import io.mockk.every
import io.mockk.mockk
import io.mockk.verify
val navigator = mockk<Navigator>()
every { navigator.navigateTo(any()) } returns Unit
navigator.navigateTo("Park")
verify { navigator.navigateTo("Park") }
class Button {
private
var clickListener: (() - > Unit) ? = null
fun setOnClickListener(listener: () - > Unit) {
clickListener = listener
}
fun performClick() {
clickListener?.invoke()
}
}
class NavigationView(
private val navigator: Navigator
) {
val goToParkButton = Button()
init {
goToParkButton.setOnClickListener {
navigator.navigate("Park")
}
}
}
// Mock the dependency needed for navigationView
val navigator = mockk<Navigator>()
every { navigator.navigateTo(any()) } returns Unit
// Create the navigation view to test
val navigationView = NavigationView(navigator)
// Test the button in navigation view
navigationView.goToParkButton.performClick()
verify { navigator.navigateTo("Park") }
goToParkButton.setOnClickListener {
-navigator.navigate("Park") +
navigator.navigate("Parka")
}
navigationView.goToParkButton.performClick()
// Throws as navigateTo("Park") was never called.
// MockK will mention in the error that navigateTo("Parka") was called.
verify {
navigator.navigateTo("Park")
}
verify { navigator wasNot Called }
Verify in Mockito simply means that you want to check if a certain method of a mock object has been called by specific number of times. When doing verification that a method was called exactly once, then we use:,When doing unit test, you do some assertions to check the equality between your expected result and the actual result. When you use mock objects in unit test, you may also need no to verify in Mockito that the mock object had done specific methods.,If the method was called multiple times, and you want to verify that it was called for specific times, lets say 3 times, then we use:,To better understand how verify in mockito works, check the example below.
verify(mockObject).someMethodOfMockObject(someArgument);
If the method was called multiple times, and you want to verify that it was called for specific times, lets say 3 times, then we use:
verify(mockObject, times(3)).someMethodOfMockObject(someArgument);
To better understand how verify in mockito works, check the example below.
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import java.util.List;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@RunWith(MockitoJUnitRunner.class)
public class VerifyTest {
@Mock
private List<String> mockList;
@Test
public void testMockListAdd() {
String addString = "some string";
mockList.add(addString);
//verify that the add method was called with argument 'some string'
verify(mockList).add(addString);
}
@Test
public void testMockListAddMultiple() {
String addString = "some string multiple";
mockList.add(addString);
mockList.add(addString);
mockList.add(addString);
//verify that the add method was called with argument 'some string'
verify(mockList, times(3)).add(addString);
}
}