添加其他存根

时间:2016-09-05 17:19:48

标签: java mockito guice jukito

我有以下要测试的对象:

   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处理的IOException。

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

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

3 个答案:

答案 0 :(得分: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");

我在my answer here

中列出了第二种语法的其他优点

答案 1 :(得分:1)

第二个模拟语句被第一个模拟语句覆盖(因为两个模拟语句都传递了一个String参数)。如果你想覆盖try以及通过模拟测试回顾,那么写下2个不同的测试用例。

答案 2 :(得分:1)

  

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

这个假设是错误的,因为存根调用mocks方法。你的测试方法仍然是普通的java!

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

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

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

Mockito是一段非常复杂的代码,可以尽力编写

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

表示使用when参数downloaderdownload调用anyString thenThrow模拟IOException方法String s1 = anyString(); // 1 String s2 = downloader.download(s1); // 2 when(s2).thenThrow(new IOException()); // 3 从左到右阅读。

但是,由于代码仍然是普通的java,因此调用序列实际上是:

ArgumentMatcher

在幕后,Mockito需要这样做:

  1. 为任何String参数注册download
  2. downloader模拟器上注册方法调用ArgumentMatcher,其中参数由先前注册的 ... downloader.download("testFile") ...
  3. 定义
  4. 在模拟
  5. 上注册先前注册的方法调用的操作

    如果你现在打电话

    downloader

    "testFile"模拟检查是否有IOException的动作注册(因为已经有任何String的动作)并因此抛出<?php function get_timespan_string($older, $newer) { $Y1 = $older->format('Y'); $Y2 = $newer->format('Y'); $Y = $Y2 - $Y1; $m1 = $older->format('m'); $m2 = $newer->format('m'); $m = $m2 - $m1; $d1 = $older->format('d'); $d2 = $newer->format('d'); $d = $d2 - $d1; $H1 = $older->format('H'); $H2 = $newer->format('H'); $H = $H2 - $H1; $i1 = $older->format('i'); $i2 = $newer->format('i'); $i = $i2 - $i1; $s1 = $older->format('s'); $s2 = $newer->format('s'); $s = $s2 - $s1; if($s < 0) { $i = $i -1; $s = $s + 60; } if($i < 0) { $H = $H - 1; $i = $i + 60; } if($H < 0) { $d = $d - 1; $H = $H + 24; } if($d < 0) { $m = $m - 1; $d = $d + get_days_for_previous_month($m2, $Y2); } if($m < 0) { $Y = $Y - 1; $m = $m + 12; } $timespan_string = create_timespan_string($Y, $m, $d, $H, $i, $s); return $timespan_string; } function get_days_for_previous_month($current_month, $current_year) { $previous_month = $current_month - 1; if($current_month == 1) { $current_year = $current_year - 1; //going from January to previous December $previous_month = 12; } if($previous_month == 11 || $previous_month == 9 || $previous_month == 6 || $previous_month == 4) { return 30; } else if($previous_month == 2) { if(($current_year % 4) == 0) { //remainder 0 for leap years return 29; } else { return 28; } } else { return 31; } } function create_timespan_string($Y, $m, $d, $H, $i, $s) { $timespan_string = ''; $found_first_diff = false; if($Y >= 1) { $found_first_diff = true; $timespan_string .= pluralize($Y, 'year').' '; } if($m >= 1 || $found_first_diff) { $found_first_diff = true; $timespan_string .= pluralize($m, 'month').' '; } if($d >= 1 || $found_first_diff) { $found_first_diff = true; $timespan_string .= pluralize($d, 'day').' '; } if($H >= 1 || $found_first_diff) { $found_first_diff = true; $timespan_string .= pluralize($H, 'hour').' '; } if($i >= 1 || $found_first_diff) { $found_first_diff = true; $timespan_string .= pluralize($i, 'minute').' '; } if($found_first_diff) { $timespan_string .= 'and '; } $timespan_string .= pluralize($s, 'second'); return $timespan_string; } function pluralize( $count, $text ) { return $count . ( ( $count == 1 ) ? ( " $text" ) : ( " ${text}s" ) ); } ?>