Hot questions for Using Mockito in assert

Question:

I'm trying to make some canned network respones. I have the json response for the actual request and I have Retrofit interfaces that serialize responses. I am beyond frustrated trying to set this up. What should I be doing here? It seems my options are, 1) Use a MockWebServer() 2) Use a RequestInterceptor().

While trying to use either 1 or 2, I can't for the life of me instantiate an OkHttpClient() without it failing, basically this puts every thing I try to death immediately. I get an java.lang.AssertionError because OkHttpClient is throwing this when it can't find a TLS algorithm.

 if (builder.sslSocketFactory != null || !isTLS) {
      this.sslSocketFactory = builder.sslSocketFactory;
    } else {
      try {
        SSLContext sslContext = SSLContext.getInstance("TLS");
        sslContext.init(null, null, null);
        this.sslSocketFactory = sslContext.getSocketFactory();
      } catch (GeneralSecurityException e) {
        **throw new AssertionError(); // The system has no TLS. Just give up.**
      }
    }

I've tried to keep the "javax.net.ssl" class in the android.jar using unMock, but that didn't resolve the error.

unMock {
    // URI to download the android-all.jar from. e.g. https://oss.sonatype.org/content/groups/public/org/robolectric/android-all/
    downloadFrom 'https://oss.sonatype.org/content/groups/public/org/robolectric/android-all/4.3_r2-robolectric-0/android-all-4.3_r2-robolectric-0.jar'

    keep "android.util.Log"
    keep "javax.net.ssl"
}

So basically, I've come across various examples of how to mock network requests with retrofit 2, but I can't get past this hurdle, and I'm feeling pretty defeated. I haven't seen anyone else with this problem, and I'm baffled as to how everyone is easily instantiating new OkHttpClients in all their tests.

Here are the relevant dependencies I am using.

    testCompile 'junit:junit:4.12'
    testCompile 'org.mockito:mockito-all:1.10.19'
    testCompile 'org.powermock:powermock-mockito-release-full:1.6.4'
    testCompile 'org.powermock:powermock-module-junit4:1.6.4'
    testCompile 'org.easymock:easymock:3.4'
    testCompile 'org.powermock:powermock-api-easymock:1.6.4'
    testCompile 'com.squareup.okhttp3:mockwebserver:3.2.0'

    compile 'com.squareup.retrofit2:retrofit:2.0.0'
    compile 'com.squareup.retrofit2:converter-gson:2.0.0'
    compile 'com.squareup.okhttp3:logging-interceptor:3.0.1'
    compile 'com.google.code.gson:gson:2.4'

Answer:

You need this annotation at the top of the class. Of course.

@PowerMockIgnore("javax.net.ssl.*")

Question:

I'm having trouble identifying if a Completable has been subscribed to in my tests, for example:

interface IWebApi {
    Observable<Data> download();
}

interface IDataRepository {
    Completable insert(Data data);
}

class SyncService {

    IWebApi webApi;
    IDataRepository repository;

    public SyncService(IWebApi webApi, IDataRepository repository) {
        this.webApi = webApi;
        this.repository = repository;
    }

    public Completable sync() {
        return webApi.download()
            .flatMapCompletable((Data data) -> { repository.insert(data) })
    }
}

And then in my tests:

@Test
public void syncTest() {
    Data data = new Data();
    IDataRepository repository = mock (IDataRepository.class);
    IWebApi webApi = mock (IWebApi.class);

    given(webApi.download()).willReturn(Observable.just(data));
    given(repository.insert(data)).willReturn(Completable.complete());

    TestObserver<Void> observer = new TestObserver<Void>();
    SyncService service = new SyncService(webApi, repository);
    service.sync()
            .subscribe(observer);

    observer.assertComplete();
    verify(repository).insert(data);
}

This test will pass. But I Could rewrite the sync method without using flatMapCompletable like this:

    public Completable sync() {
        return webApi.download()
            .doOnNext((Data data) -> { repository.insert(data) })
            .ignoreElements();
    }

Then my tests would pass but code would not work because even thought I've called the insert method, I've not called subscribe() in it.

How should I proceed about this?

P.S I am new to RxJava so if I am not using the best practices I would love to know :)

Update

Fixed the mistake of not calling .ingnoreElements() pointed by Maxim Ostrovidov


Answer:

You can use test() operator for convinience:

SyncService service = new SyncService(webApi, repository);
TestObserver observer = service.sync().test();

But I Could rewrite the sync method without using flatMapCompletable like this:

public Completable sync() {
    return webApi.download()
        .doOnNext((Data data) -> { repository.insert(data) })
}

This won't compile because doOnNext is used only to invoke actions on items, not changing the stream return type. In your case method is expecting Completable but actually it will be Observable<Data>.

Even if you force change the eventual stream type:

public Completable sync() {
    return webApi.download()
        .doOnNext((Data data) -> { repository.insert(data) })
        .ignoreElements(); //converts to Completable
}

repository.insert(data) will not be invoked because doOnNext is not subscribing to anything you passed and not returning anything:

//under the hood of lambdas
.doOnNext(new Consumer<Data>() {
    @Override
    public void accept(Data data) throws Exception {

    }
})

Your initial code is the best for what you want to achieve:

public Completable sync() {
    return webApi.download()
        .flatMapCompletable((Data data) -> { repository.insert(data) })
}

flatMapCompletable subscribes to passed Completable using items emitted by Observable:

.flatMapCompletable(new Function<Data, CompletableSource>() {
    @Override
    public CompletableSource apply(Data data) throws Exception {
        return repository.insert(data);
    }
})

Edit

To test the fact of repository.insert subscription you can use another TestObserver and Completable with applied doOnSubscribe:

TestObserver repositoryInsertObserver = TestObserver.create();
Completable insertCompletable = Completable.complete()
    .doOnSubscribe(d -> repositoryInsertObserver.onSubscribe(d));

//pass completable to your mock
given(repository.insert(data)).willReturn(insertCompletable);

//and verify that subscription took place
repositoryInsertObserver.assertSubscribed();

Question:

I have a method that looks that looks something like:

public Response methodA(ParamObject po, Supplier<Response> supplier)

the Supplier contains a call to a method on another class.

I am attempting to wrap some code in the Supplier in a more complex set of logic, something akin to a Strategy pattern, it does make the code easier to follow.

It looks something like:

public Controller {    
   private Helper helper;
   private Delegate delegate;

   public void doSomething() {
     ParamObject po = ....
     delegate.methodA(po, () -> {
         helper.doSomethingElse(v1, v2);
     }
   }

}

In my test for Controller I have mocked both Helper and Delegate, I wish to validate that helper.doSomething is called with the correct parameter values, and then return a mocked response.

Given that delegate is a mock, the Supplier is never actually executed, so no verification of the calls to helper can be mocked or verified.

Is it possible to do this? It feels like I should be able to tell mockito to capture the lambda, and or the variables the lambda itself captured and assert they are the right values return my mock response if they are the values I was looking for.


Answer:

Assuming that your class Helper looks like this:

public class Helper {
    public Response doSomethingElse(String v1, String v2) {
        // rest of the method here
    }
}

Then it could be done like this:

Helper helper = mock(Helper.class);
// a and b are the expected parameters
when(helper.doSomethingElse("a", "b")).thenReturn(new Response());
// a and c are not the expected parameters
when(helper.doSomethingElse("a", "c")).thenThrow(new AssertionError());

Delegate delegate = mock(Delegate.class);
// Whatever the parameters provided, simply execute the supplier to 
// get the response to provide and to get an AssertionError if the
// parameters are not the expected ones
when(delegate.methodA(any(), any())).then(
    new Answer<Response>() {
        @Override
        public Response answer(final InvocationOnMock invocationOnMock) throws Throwable {
            return ((Supplier<Response>) invocationOnMock.getArguments()[1]).get();
        }
    }
);

Controller controller = new Controller();
controller.helper = helper;
controller.delegate = delegate;
controller.doSomething();

Question:

i've been trying assert that my Set has collection with given property with hamcrest, using this solution, but i have :

java.lang.NoSuchMethodError: org.hamcrest.Matcher.describeMismatch(Ljava/lang/Object;Lorg/hamcrest/Description;)V at org.hamcrest.Condition$Matched.matching(Condition.java:52)

imports:

import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.hasProperty;
import static org.junit.Assert.assertThat;

code:

assertThat(mySet, contains(hasProperty("id", equalTo("expectedId"))));

have You any ideas how to assert it well ?


Answer:

Well, you should try to let assertThat do the work for you.

Set<WhateverPropertyTypeYouAreUsing> expectedSet = Collections.singleton( ... create a property object with that id/value);

assertThat(mySet, is(expectedSet))

The restriction here: that assumes that your set contains only that one property value.

Otherwise, you can go for:

assertThat(mySet.contains(someProperty), is(true))

(probably with an additional message to better describe a failing assert).

Prereq: your property class should be implementing equals() in a reasonable manner.

Question:

I have to deal with a legacy application that has no tests. So before I begin refactoring I want to make sure everything works as it is.

Now imagine the following situation:

public SomeObject doSomething(final OtherObject x, final String something) {
    if(x == null) throw new RuntimeException("x may not be null!");
    ...
}

Now I want to test that null check, so to be sure it works and I don't lose it once I refactor.

So I did this

@Test(expected = RuntimeException.class)
public void ifOtherObjectIsNullExpectRuntimeException() {
    myTestObject.doSomething(null, "testString");
}

Now, this works of course.

But instead of "testString" I'd like to pass in a random String.

So I tried with:

@Test(expected = RuntimeException.class)
public void ifOtherObjectIsNullExpectRuntimeException() {
    myTestObject.doSomething(null, Mockito.anyString());
}

But this is not allowed., as I get

org.mockito.exceptions.misusing.InvalidUseOfMatchersException: ... You cannot use argument matchers outside of verifications or stubbing

I do understand the meaning of this, but I wonder whether I can still manage to do what I want without parameterizing my test or the like. The only libraries I may use are Junit, AssertJ, Mockito and Powermock.

Any ideas?


Answer:

Well, like Mockito is trying to tell you via that exception, that's not really how you'd use anyString. Such methods are only to be used by mocks.

So, why not try testing with an actual random string? My personal favorite in such a scenario: java.util.UUID.randomUUID().toString(). This will virtually always generate a brand new string that has never been used for your test before.

I'd also like to add that if you are writing tests for your SomeObject class that you should avoid mocking SomeObject's behavior. From your example, you weren't exactly doing that, but it looked like you might be going down that route. Mock the dependencies of the implementation you're trying to test, not the implementation itself! This is very important; otherwise you aren't actually testing anything.

Question:

I'm using Junit in conjunction with Mockito. I used mockito's verify method + junit assertion to do complete verification. Is this not desirable? Should we use one or the other but not both?


Answer:

There's nothing wrong with using both.

Mockito's verify is used to assert a method was called (with the expected arguments) on the given mock.

JUnit's assertXYZ is used to assert that some result has the expected value.

Both are valid verifications, and if both are relevant, both should be used.

For example, consider the following (admittedly artificial) situation:

You have an interface that performs some mathematical calculation:

public interface ValueProducer {
    public int getValue(int val);
}

And a class that doubles any result produced by it:

public class Doubler {
    public static int doubleThatResult (ValueProducer producer, int val) {
        return 2 * producer.getValue(val);
    }
}

Testing it would require to assert two things:

  1. That getValue was properly called
  2. That the result is doubled

So, e.g.:

public class DoublerTest {

    @Test
    public void testDoubleThatResult() throws Exception {
        int value = 7; // Or any other value
        int returnMock = 13; // Or any other value

        ValueProducer producerMock = mock(ValueProducer.class);
        when(producerMock.getValue(value)).thenReturn(returnMock);

        int actual = Doubler.doubleThatResult(producerMock, value);

        verify(producerMock);
        assertEquals(26, actual);
    }
}

Question:

I have a load method and a save method in a DAO and a domain class. In my application I load a domain object, update attribute values and save the object again. I wrote this test for the app:

import ...

@RunWith(MockitoJUnitRunner.class)
public class MyAppTest
{
    @Mock
    private MyDao myDao;

    @InjectMocks
    private MyApp myApp;

    @Test
    public void testMyMethod(){
        // given
        MyDomainClass myObj = new MyDomainClass();
        when(myDao.load(anyInt())).thenReturn(myObj);

        // when
        myApp.myMethod();

        // then
        ArgumentCaptor<MyDomainClass> argumentCaptor = ArgumentCaptor.forClass(MyDomainClass.class);
        verify(myDao).save(argumentCaptor.capture());
        assertThat(argumentCaptor.getValue().myInt, is(1));
    }
}

The test passes although the logic contains a bug:

public class MyApp
{
    private MyDao myDao = new MyDao();

    public void myMethod(){
        MyDomainClass myObj = myDao.load(0);
        myDao.save(myObj);
        System.out.println("Saved myObj with myInt=" + myObj.myInt); // myInt=0
        myObj.myInt = 1;
    }
}

My question is if anyone else experienced this, and what (junit) test strategy would expose the bug.

EDIT: In response to the first suggested solution, I replaced the argument captor like so:

...
@Test
public void testMyMethod(){
...
        MyDomainClass expected = new MyDomainClass();
        expected.myInt = 1;
        verify(myDao).save(eq(expected));
}

and the test still passes. The reason is the same: by the time verify is invoked, the value of myInt is 1 in both instances. I'm trying to verify that save was invoked with myInt of myObj set to 0, i.e. this test should fail.

My question was also if there is a general thing, e.g. a different test strategy that I should consider. Are ArgumentCaptors a bad choice in some cases? I know I could write an integration test instead, but imo this should be testable in a unit test.


Answer:

By the time this is invoked ...

assertThat(argumentCaptor.getValue().myInt, is(1));

... the value of myInt is 1 since it is set to that value inside myApp.myMethod(); which is invoked before the verification.

Using an Answer

If you want to assert against the state of MyDomainClass as it was when myDao.save() was invoked then you'll need to capture that state via an answer in the 'when' stage.

Since Mockito records a reference to the MyDomainClass instance passed to myDao.save() (rather than a copy of it) you could use an Answer to record your own copy and then assert against that copy.

For example:

@Test
public void testMyMethod(){
    // given
    MyDomainClass myObj = new MyDomainClass();
    when(myDao.load(anyInt())).thenReturn(myObj);

    AtomicReference<MyDomainClass> actualSavedInstance = new AtomicReference<>();

    doAnswer(invocation -> {
        MyDomainClass supplied = (MyDomainClass) invocation.getArguments()[0];

        // copy/clone state from supplied - which represents the instance passed to save - into a separate
        // instance which can be used for an assertion
        MyDomainClass actual = new MyDomainClass();
        actual.myInt = supplied.myInt;
        actualSavedInstance.set(actual);
        return null;
    }).when(myDao).save(myObj);

    // when
    myApp.myMethod();

    assertThat(actualSavedInstance.get().myInt, is(0));
}

An Alternative

An alternative to this might be to delegate the 'post update increment' within MyDao.save() to a separate actor and then mock that actor and verify it.

For example, change MyApp as follows:

public void myMethod(){
    MyDomainClass myObj = myDao.load(0);
    myDao.save(myObj);
    System.out.println("Saved myObj with myInt=" + myObj.myInt); // myInt=0

    // the handler will do this: myObj.myInt = 1;
    postSaveHandler.handle(myObj);
}

And then implement the test like so:

@RunWith(MockitoJUnitRunner.class)
public class MyAppTest
{
    @Mock
    private MyDao myDao;
    @Mock
    private PostSaveHandler postSaveHandler;

    @InjectMocks
    private MyApp myApp;

    @Test
    public void testMyMethod(){
        // given
        MyDomainClass myObj = new MyDomainClass();
        when(myDao.load(anyInt())).thenReturn(myObj);

        // when
        myApp.myMethod();

        ArgumentCaptor<MyDomainClass> argumentCaptor = ArgumentCaptor.forClass(MyDomainClass.class);
        verify(myDao).save(argumentCaptor.capture());
        assertThat(argumentCaptor.getValue().myInt, is(0));

        verify(postSaveHandler).handle(myObj);
    }
}

Question:

If I make a JUnit Mockito test in the following method, it fails with org.opentest4j.AssertionFailedError: expected: not null. But the Mockito-(Parameter-)Test before with verify() and Assertions.assertNotNull() is ok. What am I doing wrong or what I don't understand? Here's my code:

JUnit5/mock-Test:

@Mock
private MyentityAServiceImpl myentityAServiceImplmock;
@Captor
private ArgumentCaptor<MyentityA> myentityAArgument;
@Mock
private MyentityBdao myentityBdaomock;
@Mock
private MyentityB myentityBmock;
@Mock
private Logger loggermock;
@InjectMocks
private MyentityBServiceImpl teServiceImpl;

@Test
public void setMyentityAOfTeIfNullByLanr17() {
    myentityBmock.setLanr7( "1234567" );
    final MyentityA myentityA = new MyentityA();
    mockito.when( myentityAServiceImplmock.findMyentityAByLanr17( myentityBmock.getLanr7() ) ).thenReturn( myentityA );
    mockito.when( myentityBdaomock.save( myentityBmock ) ).thenReturn( myentityBmock );
    myentityBmock = teServiceImpl.setMyentityAOfTeIfNullByLanr17( myentityBmock );
    mockito.verify( myentityBmock ).setMyentityA( myentityAArgument.capture() );
    Assertions.assertNotNull( myentityAArgument );
    Assertions.assertNotNull( myentityBmock.getMyentityA() );  // --> org.opentest4j.AssertionFailedError: expected: not <null>
}

Method to test:

  public MyentityB setMyentityAOfTeIfNullByLanr17( final MyentityB entity ) {
    MyentityA myentityA = entity.getMyentityA();
    if ( myentityA != null ) {
        return entity;
    }
    final String lanr17 = entity.getLanr7();
    myentityA = myentityAServiceImpl.findMyentityAByLanr17( lanr17 );
    if ( myentityA != null ) {
        entity.setMyentityA( myentityA );
        entity.setModuser( "root" );
        return myentityBdao.save( entity );
    }
    return entity;
}

Answer:

Sorry your testing code is really too complex. It describes too finely the flow of invocations of the objects manipulated in the method under test. Besides you mock many things : dependencies, parameters of the method under tests. At last you assign to the variable referencing the mocked parameter the return of the method under test. It makes things really unclear.

A test has to be straight understandable and that is not. It took me about 5 mn to understand the error cause. It is a lot for such a simple code.

This assertion failure :

Assertions.assertNotNull( myentityBmock.getMyentityA() );  // --> org.opentest4j.AssertionFailedError: expected: not <null>

is due to the fact that in the tested method getMynEntityA() can only be null as myentityBmock is a mock and setting a field as you do here will have no effect on the real field and the associated getter behavior :

if ( myentityA != null ) {
    entity.setMyentityA( myentityA ); // here you invoke a mocked method.
    entity.setModuser( "root" );
    return myentityBdao.save( entity );
}

In fact with your way of testing that mainly describes the invocation flow of the tested method, that is enough :

mockito.verify( myentityBmock ).setMyentityA( myentityAArgument.capture() );

as you cannot test the side effect of setMyentityA().

But really I strongly advise you to unit test your method without mocking the parameter of the tested method. It could look like :

@Test
public void setMyentityAOfTeIfNullByLanr17() {
    MyentityB entityB = new MyentityB(...) ;
    entityB.setLanr7( "1234567" );
    final MyentityA myentityA = new MyentityA();
    mockito.when( myentityAServiceImplmock.findMyentityAByLanr17( entityB.getLanr7() ) ).thenReturn( myentityA );
    mockito.when( myentityBdaomock.save(entityB) ).thenReturn(entityB);

    // action
    MyentityB entityActualB = teServiceImpl.setMyentityAOfTeIfNullByLanr17(entityB);

    // Perform content/logic assertion and no flow assertion :
    Assertions.assertEquals(myEntityA, entityActualB.getMyEntityA());
    Assertions.assertEquals("root", entityActualB.getModuser());
}

No tested code at all but it should help you to understand my intention.

Question:

My test will pass when I exclude the verifyNoMoreInteractions(daoInteractor) line. I thought placing the verifyNoMoreInteractions() at the end of the test as I have done would mean this failure wouldn't happen?

Alternatively, it will pass if I exclude the assertEquals() line and keep verifyNoMoreInteractions().

Am I over testing?

when(daoInteractor.getViewedReleases()).thenReturn(viewedReleases);

verify(daoInteractor, times(1)).getViewedReleases();
line 210: assertEquals(daoInteractor.getViewedReleases(), viewedReleases);

// line 216: verifyNoMoreInteractions(daoInteractor);

Stacktrace:

org.mockito.exceptions.verification.NoInteractionsWanted: 
No interactions wanted here:
-> at bj.main.MainPresenterUnitTest.buildRecommendationsError_ControllerError(MainPresenterUnitTest.java:216)
But found this interaction on mock 'daoInteractor':
-> at bj.main.MainPresenterUnitTest.buildRecommendationsError_ControllerError(MainPresenterUnitTest.java:210)
***
For your reference, here is the list of all invocations ([?] - means unverified).
1. -> at bj.main.MainPresenter.buildRecommendations(MainPresenter.java:160)
2. [?]-> at bj.main.MainPresenterUnitTest.buildRecommendationsError_ControllerError(MainPresenterUnitTest.java:210)


    at bj.main.MainPresenterUnitTest.buildRecommendationsError_ControllerError(MainPresenterUnitTest.java:216)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
    at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.mockito.internal.runners.DefaultInternalRunner$1.run(DefaultInternalRunner.java:68)
    at org.mockito.internal.runners.DefaultInternalRunner.run(DefaultInternalRunner.java:74)
    at org.mockito.internal.runners.StrictRunner.run(StrictRunner.java:39)
    at org.mockito.junit.MockitoJUnitRunner.run(MockitoJUnitRunner.java:161)
    at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:117)
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:42)
    at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:262)
    at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:84)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:147)


Process finished with exit code -1

Answer:

The problem is not with verifyNoMoreInteractions(daoInteractor);

At this line you are expecting method call:

verify(daoInteractor, times(1)).getViewedReleases();

However the call didn't happen yet. You are not telling mockito that you expect call to be happen in the future, you are verifying that the call already occurred.

The solution is to move the line after the call:

assertEquals(daoInteractor.getViewedReleases(), viewedReleases);
verify(daoInteractor, times(1)).getViewedReleases();
verifyNoMoreInteractions(daoInteractor);

Question:

I'm trying to familiarise myself with JUnit/Mockito and am using the below method to attempt some unit tests:

public FSDataInputStream getObj(String hName, Path p) throws IOException {

    String myKey = pathToKey(hName, p);
    FileStatus status = memoryCache.getStatus(p.toString());
    if (status == null) {
      status = getStatus(hName, p, "getObj");
    }
    if (status.isDirectory()) {
        throw new FileNotFoundException("Can't open " + path
  + " because it is a directory");
    }
    InputStream inputStream = new InputStream(bucket, myKey,
    status.getLen(), client, readAhead, inputPolicy);

    return new FSDataInputStream(inputStream);
}

I wish to test that the fileNotFoundException is thrown if status.isDirectory == true.

I believe I must invoke the getObj() method and for if (status.isDirectory()) I must ensure the value is true. I think this is done with when(fileStatus.isDirectory()).thenReturn(true); I'm not sure how to invoke the method and make sure this takes place.

So far I've got this JUnit but it doesn't seem to be correct as its returning the below error:

public class ClientTest {
    MemoryCache memoryCache = mock(MemoryCache.class);
    FileStatus fileStatus = mock(FileStatus.class);

    @Rule
    public final ExpectedException exception = ExpectedException.none();

    @Test
    public void getObjTest() throws Exception {
        Path path = new Path("xyz://aa-bb-cc/data7-1-23-a.txt");

        when(memoryCache.getFileStatus(path.toString())).thenReturn(fileStatus);
        when(fileStatus.isDirectory()).thenReturn(true);
        exception.expect(FileNotFoundException.class);
    }
}

java.lang.AssertionError: Expected test to throw an instance of java.io.FileNotFoundException at org.junit.Assert.fail(Assert.java:88) at org.junit.rules.ExpectedException.failDueToMissingException(ExpectedException.java:263) at org.junit.rules.ExpectedException.access$200(ExpectedException.java:106) at org.junit.rules.ExpectedException$ExpectedExceptionStatement.evaluate(ExpectedException.java:245) at org.powermock.modules.junit4.internal.impl.PowerMockJUnit47RunnerDelegateImpl$PowerMockJUnit47MethodRunner.executeTest(PowerMockJUnit47RunnerDelegateImpl.java:91) at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.runBeforesThenTestThenAfters(PowerMockJUnit44RunnerDelegateImpl.java:282) at org.junit.internal.runners.MethodRoadie.runTest(MethodRoadie.java:87) at org.junit.internal.runners.MethodRoadie.run(MethodRoadie.java:50) at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.invokeTestMethod(PowerMockJUnit44RunnerDelegateImpl.java:207) at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.runMethods(PowerMockJUnit44RunnerDelegateImpl.java:146) at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$1.run(PowerMockJUnit44RunnerDelegateImpl.java:120) at org.junit.internal.runners.ClassRoadie.runUnprotected(ClassRoadie.java:34) at org.junit.internal.runners.ClassRoadie.runProtected(ClassRoadie.java:44) at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.run(PowerMockJUnit44RunnerDelegateImpl.java:122) at org.powermock.modules.junit4.common.internal.impl.JUnit4TestSuiteChunkerImpl.run(JUnit4TestSuiteChunkerImpl.java:106) at org.powermock.modules.junit4.common.internal.impl.AbstractCommonPowerMockRunner.run(AbstractCommonPowerMockRunner.java:53) at org.powermock.modules.junit4.PowerMockRunner.run(PowerMockRunner.java:59) at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86) at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:678) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)

Can anybody advise what I'm doing wrong?


Answer:

1) Uncomment the first when statement as it is necessary for the next when set-up to work.

2) Invoke the method under test

3) (Optional) use annotations for mocking:

public class ClientTest {

    @Spy
    @InjectMocks
    private Client clientSpy = new Client();

    @Mock
    MemoryCache memoryCache;
    @Mock
    FileStatus fileStatus;

    @Rule
    public final ExpectedException exception = ExpectedException.none();

    @Before
    public void init(){
       MockitoAnnotations.initMocks(this);
    }

    @Test
    public void getObjTest() throws Exception {
       // Arrange
       Path path = new Path("xyz://aa-bb-cc/data7-1-23-a.txt");

        doReturn(Mockito.anyString()).when(clientSpy)
           .pathToKey(Mockito.anyString(), Mockito.anyString());         

        when(memoryCache.getFileStatus(path.toString()))
           .thenReturn(fileStatus);

        when(fileStatus.isDirectory()).thenReturn(true);

        exception.expect(FileNotFoundException.class);

        // Act
        clientSpy.getObj(name, path);
    }
}