断言 Optional 具有一定的价值
Assert that Optional has certain value
我有一个 Java 方法 returns 一个 Optional。
我想为它编写一个易于阅读的单元测试,断言
返回的 Optional 有一个值(即 Optional 不为空)并且
返回值等于预期值。
假设我测试的方法是
Optional<String> testedMethod(){
return Optional.of("actual value");
}
我为此使用 Hamcrest Optional:
import static com.github.npathai.hamcrestopt.OptionalMatchers.hasValue;
import org.junit.Test;
public class MyUnitTests {
@Test
public void testThatOptionalHasValue(){
String expectedValue = "actual value";
assertThat(testedMethod(), hasValue(expectedValue));
}
}
您可以将 Hamcrest Optional 添加到您的依赖项中,方法是将其包含在 build.gradle
:
dependencies {
testCompile 'junit:junit:4.12'
testCompile 'com.github.npathai:hamcrest-optional:1.0'
}
为什么不使用 isPresent()
和 get()
?
您还可以使用 AssertJ 进行流畅的断言
@Test
public void testThatOptionalIsNotEmpty() {
assertThat(testedMethod()).isNotEmpty();
}
@Test
public void testThatOptionalHasValue() {
assertThat(testedMethod()).hasValue("hello");
}
下面的方法使用了这样一个事实,即您可以为可选的指定默认值 return。所以你的测试方法可能是这样的:
@test
public void testThatOptionalHasValue() {
String expectedValue = "actual value";
String actualValue = Optional.ofNullable(testedMethod()).orElse("not " + expectedValue);
assertEquals("The values are not the same", expectedValue, actualValue);
}
这保证如果您的方法return为空,则结果不会与预期值相同。
TL;DR Ole V. V. 建议的最佳整体方法:
assertEquals(Optional.of("expected"), opt);
下面讨论其他替代方案。
有几种不同的方法可以做到这一点,具体取决于您对测试结果的清晰度与测试写作的简洁性的偏好。对于这个答案,我将坚持使用 "stock" Java 8 和 JUnit 4,没有其他依赖项。
一种方法,如 中所建议的,就是简单地写
assertEquals("expected", opt.get());
这主要有效,但如果 Optional 为空,则 get()
将抛出 NoSuchElementException
。这反过来会导致 JUnit 发出错误信号而不是失败信号,这可能不是您想要的。除非您已经知道 get()
在这种情况下抛出 NSEE,否则还不是很清楚发生了什么。
另一个选择是
assertTrue(opt.isPresent() && "expected".equals(opt.get()));
这在大多数情况下也有效,但如果存在不匹配,它不会报告实际值,这可能会给调试带来不便。
另一种选择是
assertEquals("expected", opt.orElseThrow(AssertionFailedError::new));
这会给出正确的失败并在不匹配时报告实际值,但对于抛出 AssertionFailedError
的原因并不是很明确。您可能不得不盯着它看一会儿,直到您意识到当 Optional 为空时会抛出 AFE。
还有一个选择是
assertEquals("expected", opt.orElseThrow(() -> new AssertionFailedError("empty")));
但这开始变得冗长了。
你可以把它分成两个断言,
assertTrue(opt.isPresent());
assertEquals("expected", opt.get());
但您之前曾因为冗长而反对 。在我看来,这并不是非常冗长,但它确实有一些认知开销,因为有两个单独的断言,并且它依赖于第二个只有在第一个成功时才被检查。这并没有错,但有点微妙。
最后,如果您愿意创建一些自己的基础架构,您可以创建一个适当命名的 AssertionFailedError
子类并像这样使用它:
assertEquals("expected", opt.orElseThrow(UnexpectedEmptyOptional::new));
最后,在另一条评论中,Ole V. V. 建议
assertEquals(Optional.of("correct"), opt);
这很好用,事实上这可能是最好的。
我更喜欢在断言之前将 .orElse(null) 应用于返回的 Optional。
方法 assertEquals 可以与包含预期值的 Optional 一起使用(或者在使用 FEST 断言时使用 assertThat(result).isEqualTo(expected))。
但使用 .orElse 的好处是结果具有正确的类型,并且如果该方法不是可选的,则允许执行您可能想要执行的所有检查:
- == 运算符(或使用 FEST 时的 isSame 方法)
- compareTo 和使用 compareTo 的方法
- startsWith、endsWith、contains、字符串的长度
- ...
使用期望值的 Optional 不允许所有这些事情。
我有一个 Java 方法 returns 一个 Optional。 我想为它编写一个易于阅读的单元测试,断言
返回的 Optional 有一个值(即 Optional 不为空)并且
返回值等于预期值。
假设我测试的方法是
Optional<String> testedMethod(){
return Optional.of("actual value");
}
我为此使用 Hamcrest Optional:
import static com.github.npathai.hamcrestopt.OptionalMatchers.hasValue;
import org.junit.Test;
public class MyUnitTests {
@Test
public void testThatOptionalHasValue(){
String expectedValue = "actual value";
assertThat(testedMethod(), hasValue(expectedValue));
}
}
您可以将 Hamcrest Optional 添加到您的依赖项中,方法是将其包含在 build.gradle
:
dependencies {
testCompile 'junit:junit:4.12'
testCompile 'com.github.npathai:hamcrest-optional:1.0'
}
为什么不使用 isPresent()
和 get()
?
您还可以使用 AssertJ 进行流畅的断言
@Test
public void testThatOptionalIsNotEmpty() {
assertThat(testedMethod()).isNotEmpty();
}
@Test
public void testThatOptionalHasValue() {
assertThat(testedMethod()).hasValue("hello");
}
下面的方法使用了这样一个事实,即您可以为可选的指定默认值 return。所以你的测试方法可能是这样的:
@test
public void testThatOptionalHasValue() {
String expectedValue = "actual value";
String actualValue = Optional.ofNullable(testedMethod()).orElse("not " + expectedValue);
assertEquals("The values are not the same", expectedValue, actualValue);
}
这保证如果您的方法return为空,则结果不会与预期值相同。
TL;DR Ole V. V. 建议的最佳整体方法:
assertEquals(Optional.of("expected"), opt);
下面讨论其他替代方案。
有几种不同的方法可以做到这一点,具体取决于您对测试结果的清晰度与测试写作的简洁性的偏好。对于这个答案,我将坚持使用 "stock" Java 8 和 JUnit 4,没有其他依赖项。
一种方法,如
assertEquals("expected", opt.get());
这主要有效,但如果 Optional 为空,则 get()
将抛出 NoSuchElementException
。这反过来会导致 JUnit 发出错误信号而不是失败信号,这可能不是您想要的。除非您已经知道 get()
在这种情况下抛出 NSEE,否则还不是很清楚发生了什么。
另一个选择是
assertTrue(opt.isPresent() && "expected".equals(opt.get()));
这在大多数情况下也有效,但如果存在不匹配,它不会报告实际值,这可能会给调试带来不便。
另一种选择是
assertEquals("expected", opt.orElseThrow(AssertionFailedError::new));
这会给出正确的失败并在不匹配时报告实际值,但对于抛出 AssertionFailedError
的原因并不是很明确。您可能不得不盯着它看一会儿,直到您意识到当 Optional 为空时会抛出 AFE。
还有一个选择是
assertEquals("expected", opt.orElseThrow(() -> new AssertionFailedError("empty")));
但这开始变得冗长了。
你可以把它分成两个断言,
assertTrue(opt.isPresent());
assertEquals("expected", opt.get());
但您之前曾因为冗长而反对
最后,如果您愿意创建一些自己的基础架构,您可以创建一个适当命名的 AssertionFailedError
子类并像这样使用它:
assertEquals("expected", opt.orElseThrow(UnexpectedEmptyOptional::new));
最后,在另一条评论中,Ole V. V. 建议
assertEquals(Optional.of("correct"), opt);
这很好用,事实上这可能是最好的。
我更喜欢在断言之前将 .orElse(null) 应用于返回的 Optional。
方法 assertEquals 可以与包含预期值的 Optional 一起使用(或者在使用 FEST 断言时使用 assertThat(result).isEqualTo(expected))。
但使用 .orElse 的好处是结果具有正确的类型,并且如果该方法不是可选的,则允许执行您可能想要执行的所有检查:
- == 运算符(或使用 FEST 时的 isSame 方法)
- compareTo 和使用 compareTo 的方法
- startsWith、endsWith、contains、字符串的长度
- ...
使用期望值的 Optional 不允许所有这些事情。