【问题标题】:JUnit AssertionError - Expected exception not thrownJUnit AssertionError - 未抛出预期的异常
【发布时间】:2018-01-16 09:11:45
【问题描述】:

我正在尝试熟悉 JUnit/Mockito 并使用以下方法尝试一些单元测试:

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

如果 status.isDirectory == true,我希望测试是否抛出了 fileNotFoundException。

我相信我必须调用 getObj() 方法,并且对于 if (status.isDirectory()),我必须确保该值为 true。我认为这是通过when(fileStatus.isDirectory()).thenReturn(true); 完成的。我不确定如何调用该方法并确保它发生。

到目前为止,我已经有了这个 JUnit,但它似乎不正确,因为它返回以下错误:

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:预期的测试会抛出 java.io.FileNotFoundException 的实例 在 org.junit.Assert.fail(Assert.java:88) 在 org.junit.rules.ExpectedException.failDueToMissingException(ExpectedException.java:263) 在 org.junit.rules.ExpectedException.access$200(ExpectedException.java:106) 在 org.junit.rules.ExpectedException$ExpectedExceptionStatement.evaluate(ExpectedException.java:245) 在 org.powermock.modules.junit4.internal.impl.PowerMockJUnit47RunnerDelegateImpl$PowerMockJUnit47MethodRunner.executeTest(PowerMockJUnit47RunnerDelegateImpl.java:91) 在 org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.runBeforesThenTestThenAfters(PowerMockJUnit44RunnerDelegateImpl.java:282) 在 org.junit.internal.runners.MethodRoadie.runTest(MethodRoadie.java:87) 在 org.junit.internal.runners.MethodRoadie.run(MethodRoadie.java:50) 在 org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.invokeTestMethod(PowerMockJUnit44RunnerDelegateImpl.java:207) 在 org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.runMethods(PowerMockJUnit44RunnerDelegateImpl.java:146) 在 org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$1.run(PowerMockJUnit44RunnerDelegateImpl.java:120) 在 org.junit.internal.runners.ClassRoadie.runUnprotected(ClassRoadie.java:34) 在 org.junit.internal.runners.ClassRoadie.runProtected(ClassRoadie.java:44) 在 org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.run(PowerMockJUnit44RunnerDelegateImpl.java:122) 在 org.powermock.modules.junit4.common.internal.impl.JUnit4TestSuiteChunkerImpl.run(JUnit4TestSuiteChunkerImpl.java:106) 在 org.powermock.modules.junit4.common.internal.impl.AbstractCommonPowerMockRunner.run(AbstractCommonPowerMockRunner.java:53) 在 org.powermock.modules.junit4.PowerMockRunner.run(PowerMockRunner.java:59) 在 org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86) 在 org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38) 在 org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459) 在 org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:678) 在 org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382) 在 org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)

谁能告诉我我做错了什么?

【问题讨论】:

  • 你为什么第一次评论是什么时候?似乎是正确的选择
  • 我在实验的时候把它注释掉了。当我发布查询时,我一定忘记取消注释。会更新。

标签: java unit-testing junit mockito junit4


【解决方案1】:

getObj 方法必须在一个类中声明(我们在 OP 中看不到),但我们假设它在这个类中:

public class Foo {
    private MemoryCache memoryCache;

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

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

现在,您的测试可能如下所示:

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

注意事项:

  • 你必须在你的测试中调用getObj
  • getObj 调用必须进入 if (status.isDirectory()) { ... }
  • 您必须指示模拟的MemoryCache 返回模拟的FileStatus
  • isDirectory被调用时,你必须指示被模拟的FileStatus返回true
  • 您必须将模拟的MemoryCache 提供给正在测试的Foo 实例,在上面的示例中,这是通过构造函数注入完成的

【讨论】:

  • 感谢@glytching 的回复。我使用了第一个答案,但可以看到这也可以。
【解决方案2】:

1)取消注释第一个when 语句,因为它是下一个when 设置工作所必需的。

2) 调用被测方法

3)(可选)使用注解进行模拟:

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

【讨论】:

  • 我尝试使用您的示例,但在 FileStatus status = memoryCache.getStatus(p.toString()); 行得到了 NullPointerError。我需要做任何其他事情来确保它不为空吗?
  • 好的,开头还有一个额外的 pathToKey 方法,您可能需要模拟它。通过监视被测类。此外,您还需要使用 InjectMocks 注入缓存
  • 终于搞定了。我没有 Spy 和 InjectMocks 注释。现在都在工作。感谢您的帮助。
猜你喜欢
  • 1970-01-01
  • 2017-08-06
  • 1970-01-01
  • 1970-01-01
  • 2014-05-09
  • 2017-10-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多