JUnit - Tuong-Nguyen/PreparationEduLog GitHub Wiki

ArgumentMatcher

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.

Rule

@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.

Defining Rule class

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

Answer

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());
⚠️ **GitHub.com Fallback** ⚠️