Reputation: 511
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
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
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:
getObj
inside your test getObj
invocation has to enter the if (status.isDirectory()) { ... }
blockMemoryCache
to return the mocked FileStatus
FileStatus
to return true when isDirectory
is invoked MemoryCache
to the instance of Foo
which is under-test, in the above example this is done by constructor injectionUpvotes: 2