1. Overview
1.概述
Test runner frameworks like JUnit and TestNG provide some basic assertion methods (assertTrue, assertNotNull, etc.).
像JUnit和TestNG这样的测试运行框架提供了一些基本的断言方法(assertTrue,assertNotNull,等等)。
Then there are assertion frameworks like Hamcrest, AssertJ, and Truth, which provide fluent and rich assertion methods with names that usually begin with “assertThat”.
然后是断言框架,如Hamcrest、AssertJ和Truth,它们提供流畅而丰富的断言方法,名称通常以“assertThat”开头。
JSpec is another framework that allows us to write fluent assertions closer to the way we write specifications in our natural language, albeit in a slightly different manner from other frameworks.
JSpec是另一个框架,它允许我们编写更接近于用自然语言编写规范的流畅断言,尽管其方式与其他框架略有不同。
In this article, we’ll learn how to use JSpec. We’ll demonstrate the methods required to write our specifications and the messages that will print in case of test failure.
在这篇文章中,我们将学习如何使用JSpec。我们将演示编写规范所需的方法,以及在测试失败的情况下打印的信息。
2. Maven Dependencies
2.Maven的依赖性
Let’s import the javalite-common dependency, which contains JSpec:
让我们导入javalite-common依赖关系,它包含JSpec。
<dependency>
<groupId>org.javalite</groupId>
<artifactId>javalite-common</artifactId>
<version>1.4.13</version>
</dependency>
For the latest version, please check the Maven Central repository.
关于最新版本,请查看Maven Central仓库。
3. Comparing Assertion Styles
3.比较断言的风格
Instead of the typical way of asserting based on rules, we just write the specification of behavior. Let’s look at a quick example for asserting equality in JUnit, AssertJ, and JSpec.
与典型的基于规则的断言方式不同,我们只是编写行为规范。让我们来看看在JUnit、AssertJ和JSpec中断言平等的一个快速例子。
In JUnit, we’d write:
在JUnit中,我们会写。
assertEquals(1 + 1, 2);
And in AssertJ, we’d write:
而在AssertJ中,我们会写。
assertThat(1 + 1).isEqualTo(2);
Here’s how we’d write the same test in JSpec:
下面是我们如何在JSpec中写同样的测试。
$(1 + 1).shouldEqual(2);
JSpec uses the same style as fluent assertion frameworks but omits the leading assert/assertThat keyword and uses should instead.
JSpec使用与流畅断言框架相同的风格,但省略了前面的assert/assertThat关键字,而是使用should。
Writing assertions in this way makes it easier to represent the real specifications, promoting TDD and BDD concepts.
以这种方式编写断言使其更容易表示真正的规范,促进TDD和BDD概念。
Look how this example is very close to our natural writing of specifications:
看看这个例子是如何与我们的自然书写规范非常接近的。
String message = "Welcome to JSpec demo";
the(message).shouldNotBe("empty");
the(message).shouldContain("JSpec");
4. Structure of Specifications
4.规格的结构
The specification statement consists of two parts: an expectation creator and an expectation method.
规范声明由两部分组成:一个期望创造者和一个期望方法。
4.1. Expectation Creator
4.1.期望创造者
The expectation creator generates an Expectation object using one of these statically imported methods: a(), the(), it(), $():
期待创建者使用这些静态导入的方法之一生成一个期待对象。a(), the(), it(), $():
$(1 + 2).shouldEqual(3);
a(1 + 2).shouldEqual(3);
the(1 + 2).shouldEqual(3);
it(1 + 2).shouldEqual(3);
All these methods are essentially the same — they all exist only for providing various ways to express our specification.
所有这些方法本质上都是一样的–它们的存在只是为了提供各种方式来表达我们的规范。
The only difference is that the it() method is type-safe, allowing comparison only of objects that are of the same type:
唯一的区别是,it()方法是类型安全的,只允许比较相同类型的对象。
it(1 + 2).shouldEqual("3");
Comparing objects of different types using it() would result in a compilation error.
使用it()比较不同类型的对象会导致编译错误。
4.2. Expectation Method
4.2.期待法
The second part of the specification statement is the expectation method, which tells about the required specification like shouldEqual, shouldContain.
规范声明的第二部分是期望方法,它讲述了所需的规范,如shouldEqual,shouldContain。
When the test fails, an exception of the type javalite.test.jspec.TestException displays an expressive message. We’ll see examples of these failure messages in the following sections.
当测试失败时,一个类型为javalite.test.jspec.TestException的异常会显示一个表达式信息。我们将在下面的章节中看到这些失败消息的例子。
5. Built-in Expectations
5.内置的期望值
JSpec provides several kinds of expectation methods. Let’s take a look at those, including a scenario for each that shows the failure message that JSpec generates upon test failure.
JSpec提供了几种期望方法。让我们来看看这些方法,包括每个方法的一个场景,显示JSpec在测试失败时产生的失败信息。
5.1. Equality Expectation
5.1.平等的期望
shouldEqual(), shouldBeEqual(), shouldNotBeEqual()
shouldEqual(), shouldBeEqual(), shouldNotBeEqual()
These specify that two objects should/shouldn’t be equal, using the java.lang.Object.equals() method to check for equality:
这些指定两个对象应该/不应该相等,使用java.lang.Object.equals()方法来检查是否相等。
$(1 + 2).shouldEqual(3);
Failure scenario:
失败的情况:
$(1 + 2).shouldEqual(4);
would produce the following message:
将产生以下信息。
Test object:java.lang.Integer == <3>
and expected java.lang.Integer == <4>
are not equal, but they should be.
5.2. Boolean Property Expectation
5.2.布尔属性的期望值
shouldHave(), shouldNotHave()
shouldHave(), shouldNotHave()
We use these methods to specify whether a named boolean property of the object should/shouldn’t return true:
我们使用这些方法来指定对象的一个名为boolean的属性是否应该/不应该返回true:。
Cage cage = new Cage();
cage.put(tomCat, boltDog);
the(cage).shouldHave("animals");
This requires the Cage class to contain a method with the signature:
这要求Cage类包含一个具有该签名的方法。
boolean hasAnimals() {...}
Failure scenario:
失败的情况:
the(cage).shouldNotHave("animals");
would produce the following message:
将产生以下信息。
Method: hasAnimals should return false, but returned true
shouldBe(), shouldNotBe()
shouldBe(), shouldNotBe()
We use these to specify that the tested object should/shouldn’t be something:
我们用这些来指定被测对象应该/不应该是什么。
the(cage).shouldNotBe("empty");
This requires the Cage class to contain a method with the signature “boolean isEmpty()”.
这要求Cage类包含一个签名为“boolean isEmpty() “的方法。
Failure scenario:
失败的情况:
the(cage).shouldBe("empty");
would produce the following message:
将产生以下信息。
Method: isEmpty should return true, but returned false
5.3. Type Expectation
5.3.类型预期
shouldBeType(), shouldBeA()
shouldBeType(), shouldBeA()
We can use these methods to specify that an object should be of a specific type:
我们可以使用这些方法来指定一个对象应该是一个特定的类型。
cage.put(boltDog);
Animal releasedAnimal = cage.release(boltDog);
the(releasedAnimal).shouldBeA(Dog.class);
Failure scenario:
失败的情况:
the(releasedAnimal).shouldBeA(Cat.class);
would produce the following message:
将产生以下信息。
class com.baeldung.jspec.Dog is not class com.baeldung.jspec.Cat
5.4. Nullability Expectation
5.4.无效性预期
shouldBeNull(), shouldNotBeNull()
shouldBeNull(), shouldNotBeNull()
We use these to specify that the tested object should/shouldn’t be null:
我们用这些来指定被测对象应该/不应该是null。
cage.put(boltDog);
Animal releasedAnimal = cage.release(dogY);
the(releasedAnimal).shouldBeNull();
Failure scenario:
失败的情况:
the(releasedAnimal).shouldNotBeNull();
would produce the following message:
将产生以下信息。
Object is null, while it is not expected
5.5. Reference Expectation
5.5.参考期望值
shouldBeTheSameAs(), shouldNotBeTheSameAs()
shouldBeTheSameAs(), shouldNotBeTheSameAs()
These methods are used to specify that an object’s reference should be the same as the expected one:
这些方法是用来指定一个对象的引用应该与预期的引用相同。
Dog firstDog = new Dog("Rex");
Dog secondDog = new Dog("Rex");
$(firstDog).shouldEqual(secondDog);
$(firstDog).shouldNotBeTheSameAs(secondDog);
Failure scenario:
失败的情况:
$(firstDog).shouldBeTheSameAs(secondDog);
would produce the following message:
将产生以下信息。
references are not the same, but they should be
5.6. Collection and String Contents Expectation
5.6.集合和字符串内容的期望值
shouldContain(), shouldNotContain()
We use these to specify that the tested Collection or Map should/shouldn’t contain a given element:
shouldContain(), shouldNotContain()
我们使用这些来指定被测试的Collection或Map应该/不应该包含一个给定的元素。
cage.put(tomCat, felixCat);
the(cage.getAnimals()).shouldContain(tomCat);
the(cage.getAnimals()).shouldNotContain(boltDog);
Failure scenario:
失败的情况:
the(animals).shouldContain(boltDog);
would produce the following message:
将产生以下信息。
tested value does not contain expected value: Dog [name=Bolt]
We can also use these methods to specify that a String should/shouldn’t contain a given substring:
我们还可以使用这些方法来指定一个字符串应该/不应该包含一个给定的子串:。
$("Welcome to JSpec demo").shouldContain("JSpec");
And although it may seem strange, we can extend this behavior to other object types, which are compared using their toString() methods:
虽然看起来很奇怪,但我们可以将这种行为扩展到其他对象类型,使用它们的toString()方法进行比较。
cage.put(tomCat, felixCat);
the(cage).shouldContain(tomCat);
the(cage).shouldNotContain(boltDog);
To clarify, the toString() method of the Cat object tomCat would produce:
为了澄清,猫对象tomCat的toString()方法将产生。
Cat [name=Tom]
which is a substring of the toString() output of the cage object:
这是toString()对象的cage输出的一个子串。
Cage [animals=[Cat [name=Tom], Cat[name=Felix]]]
6. Custom Expectations
6.客户的期望
In addition to the built-in expectations, JSpec allows us to write custom expectations.
除了内置的期望值之外,JSpec还允许我们编写自定义期望值。
6.1. Difference Expectation
6.1.差异预期
We can write a DifferenceExpectation to specify that the return value of executing some code should not be equal to a particular value.
我们可以写一个DifferenceExpectation来指定执行某些代码的返回值不应该等于某个特定值。
In this simple example we’re making sure that the operation (2 + 3) will not give us the result (4):
在这个简单的例子中,我们要确保(2+3)的运算不会得到(4)的结果。
expect(new DifferenceExpectation<Integer>(4) {
@Override
public Integer exec() {
return 2 + 3;
}
});
We can also use it to ensure that executing some code would change the state or value of some variable or method.
我们也可以用它来确保执行一些代码会改变一些变量或方法的状态或值。
For example, when releasing an animal from a Cage that contains two animals, the size should be different:
例如,当从包含两只动物的笼中放出一只动物时,大小应该不同。
cage.put(tomCat, boltDog);
expect(new DifferenceExpectation<Integer>(cage.size()) {
@Override
public Integer exec() {
cage.release(tomCat);
return cage.size();
}
});
Failure scenario:
失败的情况:
Here we’re trying to release an animal that doesn’t exist inside the Cage:
在这里,我们试图释放一个不存在于笼子内的动物。
cage.release(felixCat);
The size won’t be changed, and we get the following message:
尺寸不会被改变,我们得到以下信息。
Objects: '2' and '2' are equal, but they should not be
6.2. Exception Expectation
6.2.例外情况的预期
We can write an ExceptionExpectation to specify that the tested code should throw an Exception.
我们可以写一个ExceptionExpectation来指定测试的代码应该抛出一个Exception。
We’ll just pass the expected exception type to the constructor and provide it as a generic type:
我们只需将预期的异常类型传递给构造函数,并将其作为一个通用类型提供。
expect(new ExceptionExpectation<ArithmeticException>(ArithmeticException.class) {
@Override
public void exec() throws ArithmeticException {
System.out.println(1 / 0);
}
});
Failure scenario #1:
失败的情况#1:
System.out.println(1 / 1);
As this line wouldn’t result in any exception, executing it would produce the following message:
由于这一行不会导致任何异常,执行它将产生以下信息。
Expected exception: class java.lang.ArithmeticException, but instead got nothing
Failure scenario #2:
失败的情况#2:
Integer.parseInt("x");
This would result in an exception different from the expected exception:
这将导致一个与预期不同的异常。
class java.lang.ArithmeticException,
but instead got: java.lang.NumberFormatException: For input string: "x"
7. Conclusion
7.结论
Other fluent assertion frameworks provide better methods for collections assertion, exception assertion, and Java 8 integration, but JSpec provides a unique way for writing assertions in the form of specifications.
其他流畅的断言框架为集合断言、异常断言和Java 8集成提供了更好的方法,但JSpec为以规范形式编写断言提供了独特的方法。
It has a simple API that let us write our assertions like natural language, and it provides descriptive test failure messages.
它有一个简单的API,让我们像自然语言一样写我们的断言,并提供描述性的测试失败信息。
The complete source code for all these examples can be found over on GitHub – in the package com.baeldung.jspec.
所有这些例子的完整源代码都可以在GitHub上找到–在com.baeldung.jspec包中。