使用标准JUnit
断言和hamcrest的assertThat
来考虑以下测试用例:
byte b = 0;
int i = 0;
assertEquals(b, i); // success
assertThat(b, equalTo(i)); // java.lang.AssertionError: Expected: <0> but: was <0>
if (b == i) {
fail(); // test fails, so b == i is true for the JVM
}
为什么会这样? JVM的值明显相等,因为b == i
为true
,为什么hamcrest
会失败?
答案 0 :(得分:28)
Assert#assertThat
是一种通用方法。原始类型不适用于泛型。在这种情况下,byte
和int
分别被设置为Byte
和Integer
。
然后变为(assertThat
内)
Byte b = 0;
Integer i = 0;
b.equals(i);
Byte#equals(Object)
的实现检查参数是否为Byte
类型,如果不是,则立即返回false
。
另一方面,assertEquals
为Assert#assertEquals(long, long)
,在这种情况下,byte
和int
参数都会提升为long
个值。在内部,它在两个相等的原始==
值上使用long
。
请注意,此装箱转换有效,因为assertThat
声明为
public static <T> void assertThat(T actual, Matcher<? super T> matcher) {
其中byte
被Byte
T
加为int
,而Integer
被加框为equalTo
(在Number
的调用中1}}),但推断为Matcher<? super T>
以匹配class ApplicationController < ActionController::Base
protect_from_forgery with: :exception
# Devise Authentication, included this line because I know Devise messes
# with CSRF token and I'd be appreciate expert opinion on how my solution will 'play' with devise
before_action :authenticate_user!
# callback to set CSRF TOKEN for non-idempotent ajax request
after_action :add_csrf_token_to_json_request_header
private
def add_csrf_token_to_json_request_header
if request.xhr? && !request.get? && protect_against_forgery?
response.headers['X-CSRF-Token'] = form_authenticity_token
end
end
end
。
这适用于Java 8改进的通用推理。您需要显式类型参数才能使其在Java 7中运行。
答案 1 :(得分:13)
这是因为int
和byte
被装箱到Integer
和Byte
,因为hamcrest匹配器对对象进行操作,而不是对基元进行操作。因此,您要将Integer
与Byte
进行比较,Byte.equals()
的实施是:
public boolean equals(Object obj) {
if (obj instanceof Byte) {
return value == ((Byte)obj).byteValue();
}
return false;
}
和Integer.equals()
:
public boolean equals(Object obj) {
if (obj instanceof Integer) {
return value == ((Integer)obj).intValue();
}
return false;
}
换句话说,Integer
和Byte
总是不相等的。比较基元时,只需使用Assert.assertEquals
。 hamcrest匹配器功能强大,但主要用于(复杂)对象断言。