junit5
JUnit与JavaScript和SVN一起是程序员经常开始使用的一些技术,甚至没有读过一篇博客文章,更不用说一本书了。 也许这是一件好事,因为它们看起来足够简单且易于理解,因此我们可以立即使用它们而无需任何手册,但这也意味着它们还没有得到充分利用。 在本文中,我们将介绍一些我认为非常有用的JUnit功能。
参数化测试
有时我们需要使用许多不同的输入和不同的预期结果来运行相同的方法或功能。 一种方法是为每种情况创建单独的测试,或者您可以使用循环,但是要跟踪可能的测试失败的源将更加困难。
例如,如果我们有以下表示有理数的值对象:
public class RationalNumber {
private final long numerator;
private final long denominator;
public RationalNumber(long numerator, long denominator) {
this.numerator = numerator;
this.denominator = denominator;
}
public long getNumerator() {
return numerator;
}
public long getDenominator() {
return denominator;
}
@Override
public String toString() {
return String.format("%d/%d", numerator, denominator);
}
}
我们有一个名为App的服务类,其中包含一个方法转换,该方法将数字除为四舍五入的十进制小数:
public class App {
/**
* THE Logic
*
* @param number some rational number
* @return BigDecimal rounded to 5 decimal points
*/
public static BigDecimal convert(RationalNumber number) {
BigDecimal numerator = new BigDecimal(number.getNumerator()).
setScale(5, RoundingMode.HALF_UP);
BigDecimal result = numerator.divide(
new BigDecimal(number.getDenominator()),
RoundingMode.HALF_UP);
return result;
}
}
对于实际的AppTest类,我们有
@RunWith(Parameterized.class)
public class AppTest {
private RationalNumber input;
private BigDecimal expected;
public AppTest(RationalNumber input, BigDecimal expected) {
this.input = input;
this.expected = expected;
}
@Parameterized.Parameters(name = "{index}: number[{0}]= {1}")
public static Collection<Object> data() {
return Arrays.asList(new Object[][]{
{new RationalNumber(1, 2), new BigDecimal("0.50000")},
{new RationalNumber(1, 1), new BigDecimal("1.00000")},
{new RationalNumber(1, 3), new BigDecimal("0.33333")},
{new RationalNumber(1, 5), new BigDecimal("0.20000")},
{new RationalNumber(10000, 3), new BigDecimal("3333.33333")}
});
}
@Test
public void testApp() {
//given the test data
//when
BigDecimal out = App.convert(input);
//then
Assert.assertThat(out, is(equalTo(expected)));
}
}
参数化的运行器或@RunWith(Parameterized.class)启用“参数化”,或者将注有@ Parameterized.Parameters的值的集合注入到Test构造函数中,其中每个子列表都是一个参数列表。 这意味着data()方法中的每个RationalNumber对象将被注入到输入变量中,而每个BigDecimal值将是期望值,因此在我们的示例中,我们有5个测试。
注释中还添加了对生成的测试的可选自定义命名,因此“ {index}:number [{0}] = {1} ”将被data()方法中定义的适当参数和“ {index}”占位符将是测试用例索引,如下图所示
|
在IntelliJ Idea中运行参数化测试 |
JUnit规则的最简单定义是,它们在某种意义上是拦截器,并且与Spring面向方面的编程或Java EE拦截器API非常相似。 基本上,您可以在执行测试之前和之后做一些有用的事情。
好的,让我们从一些内置的测试规则开始。 其中之一是ExternalResource ,其想法是我们设置一个外部资源,并在拆卸小工具后释放该资源。 这种测试的一个经典示例是创建文件,因此,我们有一个内置的TemporaryFolder类,但我们也可以为其他资源创建自己的类:
public class TheRuleTest {
@Rule
public TemporaryFolder folder = new TemporaryFolder();
@Test
public void someTest() throws IOException {
//given
final File tempFile = folder.newFile("thefile.txt");
//when
tempFile.setExecutable(true) ;
//then
assertThat(tempFile.canExecute(), is(true));
}
}
我们本可以在@Before和@After块中完成此操作,并使用Java临时文件,但在某些测试失败的情况下,很容易忘记某些东西,并且未关闭某些文件。
例如,方法还有一个超时规则,如果在给定的时间限制内执行未完成,则测试将失败,并出现超时异常。 例如,将运行时间限制为20毫秒:
@Rule
public MethodRule globalTimeout = new Timeout(20);
我们可以实施自己的规则,以执行策略或进行各种项目特定的更改。 唯一需要做的就是为我们实现TestRule接口。
解释该行为的一个简单方案是添加一个规则,该规则在测试之前和之后都打印一些东西。
import org.junit.rules.TestRule;
import org.junit.runner.Description;
import org.junit.runners.model.Statement;
public class MyTestRule implements TestRule {
public class MyStatement extends Statement {
private final Statement statement;
public MyStatement(Statement statement) {
this.statement = statement;
}
@Override
public void evaluate() throws Throwable {
System.out.println("before statement" );
statement.evaluate();
System.out.println("after statement");
}
}
@Override
public Statement apply(Statement statement,
Description description) {
System.out.println("apply rule");
return new MyStatement(statement);
}
}
因此,既然有了规则,我们就可以在测试中使用它,因为测试只会打印出不同的值:
public class SomeTest {
@Rule
public MyTestRule folder = new MyTestRule();
@Test
public void testA() {
System.out.println("A");
}
@Test
public void testB() {
System.out.println("B");
}
}
当我们运行测试时,将在控制台输出上创建以下输出:
apply rule
before statement
A
after statement
apply rule
before statement
B
after statement
内置的一个名为ExpectedException的异常在尝试测试错误时非常有用。 另外,还有一个选项可以链接规则,这些规则在许多情况下都非常有用。
总结一下
如果您想说Spock或TestNG或在JUnit之上构建的某些库比JUnit具有更多的功能,那可能就是事实。
但是你知道吗? 我们在类的路径上并不总是有那些,并且JUnit在那里并且已经在各处使用的可能性很大。 为什么不利用它的全部潜力呢?
翻译自: https://www.javacodegeeks.com/2013/12/run-junit-run.html
junit5