3

我有以下要测试的对象:

   public class MyObject {

    @Inject
    Downloader downloader;

    public List<String> readFiles(String[] fileNames) {
        List<String> files = new LinkedList<>();
        for (String fileName : fileNames) {
            try {
                files.add(downloader.download(fileName));
            } catch (IOException e) {
                files.add("NA");
            }
        }
        return files;
    }
}

这是我的测试:

@UseModules(mockTest.MyTestModule.class)
@RunWith(JukitoRunner.class)
public class mockTest {

    @Inject Downloader downloader;
    @Inject MyObject myObject;

    private final String[] FILE_NAMES = new String[] {"fail", "fail", "testFile"};
    private final List<String> EXPECTED_FILES = Arrays.asList("NA", "NA", "mockContent");

    @Test
    public void testException() throws IOException {
        when(downloader.download(anyString()))
                .thenThrow(new IOException());

        when(downloader.download("testFile"))
                .thenReturn("mockContent");

        assertThat(myObject.readFiles(FILE_NAMES))
                .isEqualTo(EXPECTED_FILES);
    }

    public static final class MyTestModule extends TestModule {
        @Override
        protected void configureTest() {
            bindMock(Downloader.class).in(TestSingleton.class);
        }
    }
}

我正在覆盖anyString()特定参数的匹配器。我正在对该download()方法进行存根,以便它返回一个特定参数的值,否则抛出一个由MyObject.readFiles.

这里奇怪的是第二个存根 ( downloader.download("testFile")) 抛出了在第一个存根 () 中设置的 IOException downloader.download(anyString())。我已经通过在我的第一个存根中抛出一个不同的异常来验证这一点。

有人可以解释一下为什么在添加额外的存根时会引发异常吗?我认为创建存根不会调用方法/其他存根。

4

3 回答 3

2

问题是当你写

when(downloader.download("testFile")).thenReturn("mockContent");

首先要调用的是downloader.download,您已经将其存根以抛出异常。

解决方案是使用 Mockito 提供的更通用的存根语法。这种语法的优点是它在存根时不调用实际方法。

doThrow(IOException.class).when(downloader).download(anyString());
doReturn("mock content").when(downloader).download("test file");

我在这里的回答中列出了第二种语法的其他优点

于 2016-09-07T00:55:04.263 回答
1

您的第二个模拟语句被第一个模拟语句覆盖(因为两个模拟语句都传递了一个字符串参数)。如果您想通过模拟测试覆盖尝试并回溯,请编写 2 个不同的测试用例。

于 2016-09-05T22:53:24.240 回答
1

我认为创建存根不会调用方法/其他存根。

这个假设是错误的,因为存根正在调用模拟方法。您的测试方法仍然是普通的 java!

由于存根 foranyString将覆盖任何特定字符串的存根,因此您必须为两个特定参数编写两个测试或存根:

when(downloader.download("fail")).thenThrow(new IOException());

when(downloader.download("testFile")).thenReturn("mockContent");

Mockito 是一段非常复杂的代码,它尽最大努力让你可以编写

when(downloader.download(anyString())).thenThrow(new IOException());

这意味着“<code>当使用参数an调用downloaders 模拟download方法时”(即可以从左到右读取)。anyStringthenThrowIOException

但是,由于代码仍然是纯 java,调用顺序实际上是:

String s1 = anyString(); // 1
String s2 = downloader.download(s1); // 2
when(s2).thenThrow(new IOException()); // 3

在幕后,Mockito 需要这样做:

  1. ArgumentMatcher为任何 String 参数注册一个
  2. download在模拟上注册一个方法调用,downloader其中参数由先前注册的定义ArgumentMatcher
  3. 在模拟上为先前注册的方法调用注册一个动作

如果你现在打电话

 ... downloader.download("testFile") ...

downloader模拟检查是否有一个动作寄存器("testFile"有,因为已经有任何字符串的动作)并相应地抛出IOException.

于 2016-09-06T05:05:54.293 回答