我有以下要测试的对象:
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。我通过在我的第一个存根中抛出一个不同的异常来验证它。
有人可以解释为什么在添加额外的存根时抛出异常?我认为创建存根不会调用方法/其他存根。
答案 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");
中列出了第二种语法的其他优点
答案 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
参数downloader
和download
调用anyString
thenThrow
模拟IOException
方法String s1 = anyString(); // 1
String s2 = downloader.download(s1); // 2
when(s2).thenThrow(new IOException()); // 3
从左到右阅读。
但是,由于代码仍然是普通的java,因此调用序列实际上是:
ArgumentMatcher
在幕后,Mockito需要这样做:
download
downloader
模拟器上注册方法调用ArgumentMatcher
,其中参数由先前注册的 ... downloader.download("testFile") ...
如果你现在打电话
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" ) );
}
?>
。