JUnit - Tuong-Nguyen/PreparationEduLog GitHub Wiki
ArgumentMatcher is used for checking if the argument used in method call is accepted or not. It is used when defining behavior of a mock object or when verifying if a method is actually happened.
// define behavior of a mock object
when(authenticateService.login(ArgumentMatchers.anyString(), ArgumentMatchers.anyString())).thenReturn(Observable.just(false));
// verify if a method of a mock object is called
verify(authenticateService).login(ArgumentMatchers.anyString(), ArgumentMatchers.anyString());
Note: When ArgumentMatcher is used, every parameter in the method must use ArgumentMatcher.
Note: ArgumentMatchers.any() vs ArgumentMatchers.any(Class type)
ArgumentMatchers.any(): match every object (which satisfies the parameter type)
ArgumentMatchers.any(Class type): match object which is satisfies the specific type (which is derived from parameter type) - this is used quite rarely.
@Before - @After and @BeforeClass - @AfterClass are used for setting up and cleaning up environment before and after a test run. When there are many classes which have the same @Before - @After (or @BeforeClass - @AfterClass), the code is duplicated.
@Rule and @ClassRule are used for moving these code (@Before - @After or @BeforeClass - @AfterClass) into a class and used them in the classes which need them.
There are 2 ways:
- Implement TestRule interface
public class RxImmediateSchedulerRule implements TestRule {
@Override
public Statement apply(final Statement base, Description description) {
return new Statement() {
@Override
public void evaluate() throws Throwable {
RxJavaPlugins.setIoSchedulerHandler(scheduler -> Schedulers.trampoline());
RxJavaPlugins.setComputationSchedulerHandler(scheduler -> Schedulers.trampoline());
RxJavaPlugins.setNewThreadSchedulerHandler(scheduler -> Schedulers.trampoline());
RxJavaPlugins.setSingleSchedulerHandler(scheduler -> Schedulers.trampoline());
RxAndroidPlugins.setInitMainThreadSchedulerHandler(scheduler -> Schedulers.trampoline());
try {
// Code before this line are @Before
base.evaluate();
// Code after this line are @After
} finally {
RxJavaPlugins.reset();
RxAndroidPlugins.reset();
}
}
};
}
}
- Extends ExternalResource class
public class RxImmediateSchedulerRule1 extends ExternalResource {
@Override
protected void before() throws Throwable {
RxJavaPlugins.setIoSchedulerHandler(scheduler -> Schedulers.trampoline());
RxJavaPlugins.setComputationSchedulerHandler(scheduler -> Schedulers.trampoline());
RxJavaPlugins.setNewThreadSchedulerHandler(scheduler -> Schedulers.trampoline());
RxJavaPlugins.setSingleSchedulerHandler(scheduler -> Schedulers.trampoline());
RxAndroidPlugins.setInitMainThreadSchedulerHandler(scheduler -> Schedulers.trampoline());
};
@Override
protected void after() {
RxJavaPlugins.reset();
RxAndroidPlugins.reset();
};
}
Normally, when defining behavior of mock object, we only need to specify the ArgumentMatcher and the returned value. However, sometimes we need to do simple implementation for the mock object (for example: calling some methods on parameters) then Answer is the way to do that.
doAnswer(new Answer<Void>() {
@Override
public Void answer(InvocationOnMock invocation) throws Throwable {
Object[] arguments = invocation.getArguments();
if (arguments != null && arguments.length > 1 && arguments[0] != null) {
DisposableObserver<Boolean> booleanObserver = (DisposableObserver<Boolean>) arguments[0];
Observable<Boolean> observable = Observable.error(new RuntimeException("Oops, Your Driver ID or Password is incorrect"));
observable.subscribe(booleanObserver);
}
return null;
}
}).when(loginUseCase).execute(any(), any());