断言Optional具有一定的值

问题描述 投票:0回答:6

我有一个返回 Optional 的 Java 方法。 我想为它编写一个易于阅读的单元测试来断言

  1. 返回的Optional有一个值(即Optional不为空)并且

  2. 返回值等于预期值。

假设我测试的方法是

Optional<String> testedMethod(){
  return Optional.of("actual value");
}
java unit-testing option-type
6个回答
61
投票

您还可以使用 AssertJ 进行流畅的断言

@Test
public void testThatOptionalIsNotEmpty() {
    assertThat(testedMethod()).isNotEmpty();
}

@Test
public void testThatOptionalHasValue() {
    assertThat(testedMethod()).hasValue("hello");
}

43
投票

TL;DR Ole V. V. 建议了最佳整体方法:

assertEquals(Optional.of("expected"), opt);

其他替代方案将在下面讨论。

有几种不同的方法可以做到这一点,具体取决于您对测试结果的清晰度与测试编写的简洁性的喜好。对于这个答案,我将坚持使用“stock”Java 8 和 JUnit 4,没有额外的依赖项。

一种方法,正如 Ole V.V. 的评论中所建议的,就是简单地写

assertEquals("expected", opt.get());

这大多数情况下有效,但如果可选为空,则

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);

这非常有效,事实上这可能是最好的。


4
投票
我使用

Hamcrest 可选

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 可选添加到您的依赖项中,方法是将其包含在您的

build.gradle

 中:

dependencies { testCompile 'junit:junit:4.12' testCompile 'com.github.npathai:hamcrest-optional:1.0' }
    

2
投票
为什么不使用

isPresent()

get()


1
投票
下面的方法使用了这样一个事实:您可以为可选值指定默认返回值。所以你的测试方法可能是这样的:

@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); }

这保证了如果你的方法返回 null,那么结果不能与预期值相同。


1
投票
我更喜欢在断言返回的Optional之前应用.orElse(null)。

方法assertEquals可以与包含预期值的Optional一起使用(或使用FEST断言时的assertThat(result).isEqualTo(expected))。

但是使用 .orElse 的好处是结果具有正确的类型,并且允许执行您可能想要执行的所有检查(如果方法不是可选的):

    == 运算符(或使用 FEST 时的 isSame 方法)
  • compareTo 和使用compareTo 的方法
  • 字符串情况下的startsWith、endsWith、包含、长度
  • ...
使用期望值的可选值不允许所有这些事情。

© www.soinside.com 2019 - 2024. All rights reserved.