pac
pac

Reputation: 511

JUnit AssertionError - Expected exception not thrown

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?

Upvotes: 2

Views: 10818

Answers (2)

Maciej Kowalski
Maciej Kowalski

Reputation: 26572

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

Upvotes: 2

glytching
glytching

Reputation: 47995

The method getObj must be declared inside a class (we can't see that in the OP) but let's assume it is in this class:

public class Foo {
    private MemoryCache memoryCache;

    public Foo(MemoryCache memoryCache) {
        this.memoryCache = memoryCache;
    }

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

Now, your test could look like this:

public class ClientTest {
    private MemoryCache memoryCache = mock(MemoryCache.class);
    private 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");

        // create the class-under-test, supplying the mocked MemoryCache
        Foo foo = new Foo(memoryCache);

        // establish your expectations on the mocked classes
        // for this test the expectations are:
        // - memoryCache returns the mocked fileStatus    
        // - the mocked fileStatus 'is a' directory        
        when(memoryCache.getFileStatus(path.toString())).thenReturn(fileStatus);
        when(fileStatus.isDirectory()).thenReturn(true);

        // you expect a FileNotFoundExceptionException ...
        exception.expect(FileNotFoundException.class);

        // ... when you invoke getObj
        foo.getObj("aString", path);
    }
}

Notes:

  • You have to invoke getObj inside your test
  • The getObj invocation has to enter the if (status.isDirectory()) { ... } block
  • You have to instruct the mocked MemoryCache to return the mocked FileStatus
  • You have to instruct the mocked FileStatus to return true when isDirectory is invoked
  • You have to supply the mocked MemoryCache to the instance of Foo which is under-test, in the above example this is done by constructor injection

Upvotes: 2

Related Questions