Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/372.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java Junit断言复杂对象时的最佳实践_Java_Junit_Hamcrest - Fatal编程技术网

Java Junit断言复杂对象时的最佳实践

Java Junit断言复杂对象时的最佳实践,java,junit,hamcrest,Java,Junit,Hamcrest,最近我为一个遗留系统编写了很多JUnit测试 我经常会问这样一个问题:断言复杂对象的最佳方法是什么? 这是我目前的代码 public class SomeParserTest { @Test public void testParse() throws Exception { final SomeParser someParser = new SomeParser(); someParser.parse("string from some fil

最近我为一个遗留系统编写了很多JUnit测试

我经常会问这样一个问题:断言复杂对象的最佳方法是什么?

这是我目前的代码

public class SomeParserTest {

    @Test
    public void testParse() throws Exception {
        final SomeParser someParser = new SomeParser();
        someParser.parse("string from some file");

        final List<Result> listOfResults = someParser.getResults();
        assertThat(listOfResults, hasSize(5));

        assertResult(listOfResults.get(0), "20151223", 2411189L, isEmptyOrNullString(), "2.71", "16.99");
        assertResult(listOfResults.get(1), "20151229", 2411190L, isEmptyOrNullString(), "2.86", "17.9");
        assertResult(listOfResults.get(2), "20151229", 2411191L, is("1.26"), ".75", "23.95");
        assertResult(listOfResults.get(3), "20151229", 2411192L, is("2.52"), "1.5", "47.9");
        assertResult(listOfResults.get(4), "20151229", 2411193L, isEmptyOrNullString(), "2.71", "16.99");

        final List<SubResult> listofSubResuls = someParser.getSubResultOf(listOfResults.get(0));
        assertThat(listofSubResuls, hasSize(1));
        assertSubResult(listofSubResuls.get(0), 12.5D, "20151223", 1L, 14.87D, 16.99D, 0L, null, 67152L, "20151223", "2", 0L, "02411189", 56744349L);

        final List<SubResult> listofSubResuls1 = someParser.getListofBBBS(listOfResults.get(1));
        assertThat(listofSubResuls1, hasSize(2));
        assertSubResult(listofSubResuls1.get(0), 30.0D, "20151228", 1L, 12.53D, 17.9D, 0L, null, 67156L, "20151229", "2", 0L, "02411190", 56777888L);
        assertSubResult(listofSubResuls1.get(1), 33.3D, "20151228", 1L, 4.66D, 6.99D, 1L, "J", 67156L, "20151229", "2", 21L, "02411190", 56777889L);
//And 50 Lines more
    }

//  how to avoid so many parameters?
    private void assertSubResult(final SubResult subResult, final double someDouble, final String bestellDatum,
            final long someLong, final double someDouble2, final double someDouble3, final long someLong3,
            final String someString,
            final long someLong1,
            final String someString4, final String someString3, final long someLong4, final String rechnungsNummer,
            final long someLong2) {
        assertThat(subResult.getXXX(), is(nullValue()));
        assertThat(subResult.getXYX().getTag(), is(someDouble2));
        assertThat(subResult.getXYX(), is("some constant"));
//      and much more
    }

    //  how to avoid so many parameters?
    private void assertResult(final Result result, final String string1234, final long abc,
            final String string1, final String string12, final String string134) {
        assertThat(result.getXXX(), is(nullValue()));
        assertThat(result.getXYX().getTag(), is(someDouble2));
        assertThat(result.getXYX(), is("some constant"));
//      and much more
    }
}
公共类SomeParserTest{
@试验
public void testParse()引发异常{
final SomeParser SomeParser=new SomeParser();
parse(“来自某个文件的字符串”);
最终列表listOfResults=someParser.getResults();
资产(结果列表,hasSize(5));
assertResult(listOfResults.get(0),“20151223”,2411189L,isEmptyOrNullString(),“2.71”,“16.99”);
assertResult(listOfResults.get(1),“20151229”,2411190L,isEmptyOrNullString(),“2.86”,“17.9”);
资产结果(结果清单get(2),“20151229”,2411191L,为(“1.26”)、“.75”、“23.95”);
资产结果(结果清单get(3),“20151229”,2411192L,is(“2.52”),“1.5”,“47.9”);
assertResult(listOfResults.get(4),“20151229”,2411193L,isEmptyOrNullString(),“2.71”,“16.99”);
最终列表listofSubResults=someParser.getSubResultOf(listOfResults.get(0));
资产(子结果列表,hasSize(1));
资产子结果(子结果列表get(0),12.5D,“20151223”,1L,14.87D,16.99D,0L,null,67152L,“20151223”,“2”,0L,“02411189”,56744349L);
最终列表listofSubResults1=someParser.getListofBBS(listOfResults.get(1));
资产(子结果列表1,hasSize(2));
资产子结果(子结果列表1.get(0),30.0D,“20151228”,1L,12.53D,17.9D,0L,null,67156L,“20151229”,“2”,0L,“02411190”,56777888L);
资产子结果(子结果列表1.get(1),33.3D,“20151228”,1L,4.66D,6.99D,1L,“J”,67156L,“20151229”,“2”,21L,“02411190”,56777889L);
//还有50行
}
//如何避免这么多参数?
私有void assertSubResult(最终子结果SubResult、最终双精度someDouble、最终字符串bestellDatum、,
最后一段很长,最后一段很长,最后一段很长,
最后一个字符串someString,
最后的长约1,
最终字符串someString4,最终字符串someString3,最终长字符串someLong4,最终字符串Rechnungsummer,
最后的长对话(2){
断言(subResult.getXXX()是(nullValue());
断言(subResult.getXYX().getTag(),是(someDouble2));
断言(subResult.getXYX(),是(“某个常量”);
//还有更多
}
//如何避免这么多参数?
私有void资产结果(最终结果、最终字符串string1234、最终长abc、,
最终字符串1、最终字符串12、最终字符串134){
断言(result.getXXX()为(nullValue());
断言(result.getXYX().getTag(),是(someDouble2));
断言(result.getXYX(),是(“某个常量”);
//还有更多
}
}
没有简单的方法来测试这样一个解析器的每一个步骤,我也不能做那么多,因为它是遗留代码


谢谢你的帮助

我将执行以下操作,而不是长的方法签名。(伪代码,未编译时的免责声明):

然后我可以这样使用它:

new AssertResult().setXXX(123).setYYY("asdasd").check(result);

您可能希望结合junit中的
assertThat()
方法来查看Matchers。您可能会发现您的测试代码看起来更像

assertThat(listOfResults.get(0), equalTo(expectedObject));
assertThat(listOfResults.get(0)).hasXXX("someString").hasYYY(1.234)
另外,还有一种方法允许您编写帮助器类,该类使用assertJ版本的
assertThat
而不是JUnit,以流畅的方式链接关于同一对象的多个独立断言。这将使您的测试代码看起来更像

assertThat(listOfResults.get(0), equalTo(expectedObject));
assertThat(listOfResults.get(0)).hasXXX("someString").hasYYY(1.234)

作为西西弗斯,我建议使用汉克雷斯特匹配器

但是我推荐一个程序。下线

assertResult(listOfResults.get(0), "20151223", 2411189L, isEmptyOrNullString(), "2.71", "16.99");
然后可能看起来像:

assertThat(listOfResults, contains(
  ResultMatcher.matchesResult().withFirstAttribute("20151223").andSecondAttribute(2411189L)...
  ... // here the matchers for the other elements of the list
));
您将需要自定义匹配器类
ResultMatcher
,该类应具有以下格式:

class ResultMatcher extends TypeSafeMatcher<Result> {
   Matcher<String> firstAttribute = Matchers.any(String.class);
   Matcher<String> secondAttribute = Matchers.any(String.class);
   ...

   ResultMatcher withFirstAttribute(String firstAttribute) {
     this.firstAttribute = Matchers.equalTo(firstAttribute);
     return this;
   }

   ...

   public boolean matchesSafely(Result result) {
     if (!firstAttribute.matches(result.getFirstAttribute())) {
       return false
     }
     ...
     return true;
   }

}
class ResultMatcher扩展了TypeSafeMatcher{
Matcher firstAttribute=Matchers.any(String.class);
Matcher secondAttribute=Matchers.any(String.class);
...
结果匹配器withFirstAttribute(字符串firstAttribute){
this.firstAttribute=Matchers.equalTo(firstAttribute);
归还这个;
}
...
公共布尔匹配安全(结果){
如果(!firstAttribute.matches(result.getFirstAttribute())){
返回错误
}
...
返回true;
}
}
这种设计有一些优点:

  • 您不需要定义equals方法
  • 您可以为每个属性定义默认值,以便只测试您感兴趣的属性,并在默认情况下匹配其他属性
  • 测试不必检查对象的每个属性(匹配器执行此操作)

我想尝试一下assertj提取功能,例如:

// fellowshipOfTheRing is a List<TolkienCharacter>
assertThat(fellowshipOfTheRing).extracting("name", "age", "race.name")
                               .contains(tuple("Boromir", 37, "Man"),
                                         tuple("Sam", 38, "Hobbit"),
                                         tuple("Legolas", 1000, "Elf"));
//研究生奖学金是一个列表
提取(“姓名”、“年龄”、“种族、姓名”)
.包含(元组(“Boromir”,37,“Man”),
tuple(“Sam”,38,“霍比特人”),
元组(“Legolas”,1000,“Elf”);
此处详细描述了该示例:

您还可以使用特定的比较策略来比较实际结果和预期结果,最后支持逐字段比较:isEqualToComparingFieldByField、IseQualToComparingOnlygiveFields和IseQualToigningGiveFields


希望它能有所帮助

为了简化代码,我做的是测试toString()。这使得测试相对脆弱(这可能是可取的,也可能不是可取的),但易于维护。对于列表,我将toString()转换为多行输出,这样IDE就可以打开一个比较窗口来轻松查看差异。这在很多情况下都可以,但在我的情况下不行。该测试不会覆盖getter中的逻辑(是的,这是一个糟糕的实践,但它的遗留代码)。此外,已经有一个
toString
方法没有覆盖它