我最近试图在其中一个测试中断言不平等.但是我无法在hamcrest中找到合适的匹配器.我理想的想做的事情是这样的.
assertThat(2 , isNot(3));
Run Code Online (Sandbox Code Playgroud)
有什么办法吗?
我目前正在尝试为一个小型库构建一组或多或少完整的单元测试.由于我们希望允许存在不同的实现,我们希望这组测试是(a)通用的,以便我们可以重用它来测试不同的实现,并且(b)尽可能完整.对于(b)部分,我想知道是否有任何最佳实践用于测试枚举类型.例如,我有一个枚举如下:
public enum Month {
January,
February,
...
December;
}
Run Code Online (Sandbox Code Playgroud)
在这里,我想确保所有枚举类型确实存在.这甚至是必要的吗?目前我正在使用Hamcrests assertThat,如下例所示:
assertThat(Month.January, is(notNullValue()));
Run Code Online (Sandbox Code Playgroud)
缺少"January"枚举会导致编译时错误,可以通过创建缺少的枚举类型来解决.
我在这里使用Java,但我不介意你的答案是否适用于其他语言.
编辑:
由于mkato和Mark Heath都指出测试枚举可能没有必要,因为当你使用不存在的枚举类型时编译器将无法编译.但我仍然想测试这些枚举,因为我们想要构建一个单独的TCK类test.jar,它将在不同的实现上运行相同的测试.所以我的问题更像是:测试枚举类型的最佳方法是什么?
在考虑了一下后,我将上面的Hamcrest声明更改为:
assertThat(Month.valueOf("January"), is(notNullValue()));
Run Code Online (Sandbox Code Playgroud)
当1月不存在时,该声明现在抛出NPE.这种方法有什么问题吗?
所以,让我们有一个字符串列表和一个带有Hamcrest匹配器的函数,并返回matches()提供的匹配器的方法结果:
public boolean matchIt(final Matcher<? super List<String>> matcher) {
final List<String> lst = obtainListFromSomewhere();
return matcher.matches(lst);
}
Run Code Online (Sandbox Code Playgroud)
到现在为止还挺好.现在我可以轻松打电话:
matchIt(empty());
matchIt(anything());
matchIt(hasItem("item"));
matchIt(everyItem(equalToIgnoringCase("item")));
Run Code Online (Sandbox Code Playgroud)
...因为所有这些工厂静态方法都生成一个适合方法签名的匹配器Matcher<? super List<String>>.
但是,我相信该matchIt()方法也应该接受一个接受Iterable对象的匹配器:
matchIt(everyItem(anything()));
Run Code Online (Sandbox Code Playgroud)
所以我天真地改变了matchIt()方法签名:
public boolean matchIt(final Matcher<? super List<? super String>> matcher);
Run Code Online (Sandbox Code Playgroud)
但它根本不起作用.它不仅不接受everyItem(anything()),甚至不接受以前正确的everyItem(equalToIgnoringCase("item"))说法(1.7.0_05编译器版本):
actual argument Matcher<Iterable<String>> cannot be converted to Matcher<? super List<? super String>> by method invocation conversion
Run Code Online (Sandbox Code Playgroud)
什么?那么这里有什么问题?它是matchIt()方法签名还是everyItem()错误设计的Hamcrest签名?或者只是Java泛型系统无法修复?非常感谢您的评论!
编辑@rlegendi我的目的是为客户端提供一个接口来添加和执行有关列表的谓词.那是matchIt()方法.matchIt(anything())在这种情况下,调用是有意义的,客户端想知道列表是否是任何内容.调用matchIt(empty())意味着客户端想要知道列表是否为空.反之为matchIt(everyItem(equalToIgnoringCase("item")))和 …
是否有Hamcrest匹配器检查参数既不是空集合也不是空?
我想我总是可以使用
both(notNullValue()).and(not(hasSize(0))
Run Code Online (Sandbox Code Playgroud)
但我想知道是否有更简单的方法,我错过了它.
好的,我认为这将是一个简短的问题.我有一个按日期排序的ArrayList,当然我看到它有效,但我也想为它编写一个测试.
我想检查列表中的下一个值(日期)是否低于上一个值.我能够使用一些fors并添加临时列表来做到这一点,但我想知道是否有更简单的解决方案.我在hamrest文档中读到,有一些contains想法(hamrest contains)迭代一个对象(列表,地图等),但我仍然不知道下一步该做什么.
我想创建一个可以运行方法的类,直到满足返回值的条件.
看起来应该是这样的
methodPoller.poll(pollDurationSec, pollIntervalMillis)
.method(dog.bark())
.until(dog -> dog.bark().equals("Woof"))
.execute();
Run Code Online (Sandbox Code Playgroud)
我的方法poller看起来有点像这个()//跟随GuiSim回答
public class MethodPoller {
Duration pollDurationSec;
int pollIntervalMillis;
public MethodPoller() {
}
public MethodPoller poll(Duration pollDurationSec, int pollIntervalMillis) {
this.pollDurationSec = pollDurationSec;
this.pollIntervalMillis = pollIntervalMillis;
return this;
}
public <T> MethodPoller method(Supplier<T> supplier) {
return this;
}
public <T> MethodPoller until(Predicate<T> predicate) {
return this;
}
}
Run Code Online (Sandbox Code Playgroud)
但是我很难从这里开始.
在满足条件之前,如何实现对常规方法的重试?
谢谢.
假设以下简单测试:
@Test
public void test() throws Exception {
Object value = 1;
assertThat(value, greaterThan(0));
}
Run Code Online (Sandbox Code Playgroud)
测试不会编译,因为"greaterThan"只能应用于类型的实例Comparable.但我想断言这value是一个大于零的整数.我怎样才能用Hamcrest来表达呢?
简单的解决方案是通过强制转换匹配器来删除泛型:
assertThat(value, (Matcher)greaterThan(0));
Run Code Online (Sandbox Code Playgroud)
可能,但生成编译器警告并感觉不对.
一个冗长的选择是:
@Test
public void testName() throws Exception {
Object value = 1;
assertThat(value, instanceOfAnd(Integer.class, greaterThan(0)));
}
private static<T> Matcher<Object> instanceOfAnd(final Class<T> clazz, final Matcher<? extends T> submatcher) {
return new BaseMatcher<Object>() {
@Override
public boolean matches(final Object item) {
return clazz.isInstance(item) && submatcher.matches(clazz.cast(item));
}
@Override
public void describeTo(final Description description) {
description
.appendText("is instanceof …Run Code Online (Sandbox Code Playgroud) 鉴于:
int[] a = {1, 2, 3, 4};
int[] b = {1, 2, 3, 4, 5};
Run Code Online (Sandbox Code Playgroud)
如何使用hamcrest匹配器将"a"作为"b"的子集?
以下作品
assertThat(Arrays.asList(b), hasItems(a));
Run Code Online (Sandbox Code Playgroud)
但是由于我从"b"创建"a",我宁愿将"a"上的断言应用为值.就像是
assertThat(a, isSubsetOf(b));
Run Code Online (Sandbox Code Playgroud)
另外,最好避免将阵列转换为列表.
我是JUnit和Hamcrest的新手,并希望获得最佳实践建议,以便我可以决定首先学习哪些文档.
对于初学者来说,哪种assertThat方法更好?
根据去年的一个人的说法,"JUnit有assertThat方法,但是hamcrest有自己的assertThat方法做同样的事情." .
根据今年早些时候的人的说法,Hamcrest "可能会提供更好的错误消息,因为匹配器被称为描述不匹配".
在这些帖子中很难分辨出哪些版本的Junit和Hamcrest被比较了.所以我想根据最新发布的版本推荐.
我有一个场景,我从方法调用中收到一个列表,我想断言该列表包含正确的元素。一种方法是在每个元素中查找一些细节以查看要与哪个预期元素进行比较 - 例如。一个名字。然而,元素还包含一个随机生成的 UUID,我不关心比较。
然后我想一个测试工具可能会来救我。以下面的简化示例为例。
我有一个类狗:
public class Dog {
private String name;
private Integer age;
}
Run Code Online (Sandbox Code Playgroud)
它们包含在一个列表中:
List<Dog> dogs = ... many dogs
Run Code Online (Sandbox Code Playgroud)
现在我想测试该列表是否包含预期的狗,但由于某种原因我不知道某些字段 - 让我们说age. 我已经尝试过使用 assertj 和 hamcrest,但我找不到正确的解决方案,既可以比较两个列表,又可以忽略某些字段。
到目前为止,这就是我所拥有的(使用 hamcrest):
List<Dog> actualDogs = codeUndertest.findDogs(new Owner("Basti"));
List<Dog> expectedDogs = createExpectedListOfDogsWithoutTheAge();
Matcher.assertThat(actualDogs.get(0), Matcher.is(com.shazam.shazamcrest.matcher.Matchers
.sameBeanAs(expectedDogs.(0))
.ignoring("age")
))
Run Code Online (Sandbox Code Playgroud)
这有效,但它只比较 Dog 类的两个对象。我如何比较两个列表中的所有狗?
额外问题:如何在不知道顺序的情况下比较列表,或者我是否只需要断言预期的狗包含在列表中。