一、使用JUnit的一般测试语法
org.junit.Assert类里有各种断言方法,大部分情况下我们会像下面这个例子一样编写测试:
public class AssertThatTest {
private int id = 6;
private boolean trueValue = true;
private Object nullObject = null;
private String msg = "Hello World";
@Test
public void testAssert() throws Exception {
assertEquals(6, id);
assertTrue(trueValue);
assertNull(nullObject);
assertTrue(msg != null && msg.startsWith("Hello") && msg.endsWith("World"));
}
}
但是这些基本的断言有些可读性并不是很好,例如上面最后一个断言,判断一个字符串以“Hello”开头,以“Workd”结尾,由于没有assertStartWith和assertEndWith之类的函数,我们不得不自己编写表达式并断言其结果。并且因为我们没有提供失败的信息,当这个断言失败时只会抛出java.lang.AssertionError,根本不知道是因为msg为null还是msg的内容错误。
二、使用assertThat与Matcher
在org.junit.Assert中除了常用的相等、布尔、非空等断言,还有一种assertThat,需要配合org.hamcrest.Matcher使用,这种断言的语法为:
assertThat([reason, ]T actual, Matcher<? super T> matcher),其中,reason为断言失败时的输出信息,actual为断言的值或对象,matcher为断言的匹配器,里面的逻辑决定了给定的actual对象满不满足断言。
在org.hamcrest.CoreMatchers类中组织了所有JUnit内置的Matcher,调用其任意一个方法都会创建一个与方法名字相关的Matcher。
使用assertThat重写上述方法:
public class AssertThatTest {
private int id = 6;
private boolean trueValue = true;
private Object nullObject = null;
private String msg = "Hello World!";
@Test
public void testAssertThat() throws Exception {
//由于静态导入了org.haibin369.matcher.MyMatchers.*,可以调用里面的
//is(), nullValue(), containsString(), startsWith()方法,可读性更好
assertThat(id, is(6));
assertThat(trueValue, is(true));
assertThat(nullObject, nullValue());
assertThat(msg, both(startsWith("Hello")).and(endsWith("World")));
}
}
重写后的测试和之前的效果一模一样,但是可读性更好了,最后一个断言,能一眼看出来是要以“Hello”开头并以“World”结尾的字符串。如果把startsWith("Hello")改成startsWith("Helloo"),它的失败信息也比较直观:
java.lang.AssertionError:
Expected: (a string starting with "Helloo" and a string ending with "World")
but: a string starting with "Helloo" was "Hello World!"
三、自定义Matcher
现在我们有一个User对象,只包含两个变量机器setter和getter:username,password,当username和password都为“admin”时表示是管理员(Admin User)。现在我们来创建一个自己的Matcher并运用到assertThat语法中去。
首先看看org.hamcrest.Matcher接口的源码
/**
* A matcher over acceptable values.
* A matcher is able to describe itself to give feedback when it fails.
* <p/>
* Matcher implementations should <b>NOT directly implement this interface</b>.
* Instead, <b>extend</b> the {@link BaseMatcher} abstract class,
* which will ensure that the Matcher API can grow to support
* new features and remain compatible with all Matcher implementations.
* <p/>
* For easy access to common Matcher implementations, use the static factory
* methods in {@link CoreMatchers}.
* <p/>
* N.B. Well designed matchers should be immutable.
*
* @see CoreMatchers
* @see BaseMatcher
*/
public interface Matcher<T> extends SelfDescribing {
boolean matches(Object item);
void describeMismatch(Object item, Description mismatchDescription);
@Deprecated
void _dont_implement_Matcher___instead_extend_BaseMatcher_();
}
类注释上强调,Matcher实现类不应该直接实现这个接口,而应该继承org.hamcrest.BaseMatcher抽象类
public abstract class BaseMatcher<T> implements Matcher<T> {
/**
* @see Matcher#_dont_implement_Matcher___instead_extend_BaseMatcher_()
*/
@Override
@Deprecated
public final void _dont_implement_Matcher___instead_extend_BaseMatcher_() {
// See Matcher interface for an explanation of this method.
}
@Override
public void describeMismatch(Object item, Description description) {
description.appendText("was ").appendValue(item);
}
@Override
public String toString() {
return StringDescription.toString(this);
}
}
编写IsAdminMatcher,需要实现两个方法,第一个是matches,判断给定的对象是否是所期待的值,第二个是describeTo,把应该得到的对象的描述添加进Description对象中。
/**
* 断言一个给定的User对象是管理员
*/
public class IsAdminMatcher extends BaseMatcher<User> {
/**
* 对给定的对象进行断言判定,返回true则断言成功,否则断言失败
*/
@Override
public boolean matches(Object item) {
if (item == null) {
return false;
}
User user = (User) item;
return "admin".equals(user.getUsername()) && "admin".equals(user.getPassword());
}
/**
* 给期待断言成功的对象增加描述
*/
@Override
public void describeTo(Description description) {
description.appendText("Administrator with 'admin' as username and password");
}
}
执行测试:
public class AssertThatTest {
User user = new User("haibin369", "123456");
@Test
public void testAdmin() throws Exception {
assertThat(user, new IsAdminMatcher());
}
}
测试可以正常执行,但是上面的User对象并不是管理员,因此测试会失败,以下信息会输出:
java.lang.AssertionError:
Expected: Administrator with 'admin' as username and password
but: was <org.haibin369.model.User@570b13e4>
查看源代码,我们发现but后面的信息是在BaseMatcher中的describeMismatch方法输出的,通过这个信息明显不清楚到底实际上得到了什么User,因此在我们的Matcher中从写这个方法:
/**
* 当断言失败时,描述实际上得到的错误的对象。
*/
@Override
public void describeMismatch(Object item, Description description) {
if (item == null) {
description.appendText("was null");
} else {
User user = (User) item;
description.appendText("was a common user (")
.appendText("username: ").appendText(user.getUsername()).appendText(", ")
.appendText("password: ").appendText(user.getPassword()).appendText(")");
}
}
重新执行测试,得到以下失败信息:
java.lang.AssertionError:
Expected: Administrator with 'admin' as username and password
but: was a common user (username: haibin369, password: 123456)
虽然我们自定义的Matcher已经能够执行了,但是assertThat(user, new IsAdminMatcher());这段代码并没有达到之前所说的可读性更好的要求,因此,我们仿照org.hamcrest.CoreMatchers,创建一个类去创建我们自定义的Matcher:
public class MyMatchers {
public static Matcher<User> isAdmin() {
return new IsAdminMatcher();
}
}
在测试方法中静态导入该类中的所有内容,则可以像下面一样使用assertThat:
import static org.haibin369.matcher.MyMatchers.*;
public class AssertThatTest {
User user = new User("haibin369", "123456");
@Test
public void testAdmin() throws Exception {
assertThat(user, isAdmin());
}
}
分享到:
相关推荐
赠送jar包:junit-platform-launcher-1.8.0-M1.jar; 赠送原API文档:junit-platform-launcher-1.8.0-M1-javadoc.jar; 赠送源代码:junit-platform-launcher-1.8.0-M1-sources.jar; 赠送Maven依赖信息文件:junit-...
junit4单元测试报错:method initializationerror not found 缺少jar包导致,总共需要三个jar包:junit-4.11.jar,hamcrest-core-1.3.rc2.jar,hamcrest-library-1.3.rc2.jar,都在压缩包里了。
@Test:这是 JUnit4 中的核心元数据,用于标记测试方法。当 JUnit4 运行测试时,会查找所有带有 @Test 注解的方法,并逐一执行。@BeforeClass 和 @AfterClass:这两个元数据分别表示在整个测试类运行前只执行一次的...
#### 三、JUnit4 与 JUnit3 的差异 在 JUnit3 中,编写测试用例时有许多限制,比如测试类必须继承 `junit.framework.TestCase` 类,且测试方法必须以 `test` 开头。这些限制在 JUnit4 中已经被取消,取而代之的是...
JUnit 4所需system-rules.jar依赖包,主要包含:system-rules-1.16.1.jar,system-rules-1.17.1.jar,system-rules-1.18.0.jar
### JUnit4学习笔记——入门篇 #### 一、配置MyEclipse在项目中引入JUnit4.jar包 在使用JUnit4进行单元测试之前,首先需要确保开发环境已正确配置JUnit库。对于使用MyEclipse IDE的开发者来说,可以通过以下步骤...
赠送jar包:junit-jupiter-engine-5.8.2.jar; 赠送原API文档:junit-jupiter-engine-5.8.2-javadoc.jar; 赠送源代码:junit-jupiter-engine-5.8.2-sources.jar; 赠送Maven依赖信息文件:junit-jupiter-engine-...
Junit学习笔记,希望有用~~~~~~~~~~~~~~~~~~~~~~
- **集成到构建工具**:JUnit4与Maven、Gradle等构建工具无缝集成,使得测试成为项目构建的一部分。 6. **学习路径**: - 开始时,可以浏览`javadoc`了解基本API。 - 掌握基本的测试用例编写,学习如何使用注解...
JUnit 4单元测试利器 本文主要介绍了如何使用JUnit 4提供的各种功能开展有效的单元测试,并通过一个实例演示了如何使用Ant执行自动化的单元测试。下面是从中生成的相关知识点: 1. JUnit 4简介:JUnit是Java社区中...
junit-vintage-engine-5.6.2.jarjunit-vintage-engine-5.6.2.jarjunit-vintage-engine-5.6.2.jar
本人小白,开始学习Android,记录自己的错误瞬间,大神不要喷我,哈哈! 安装好android studio后,测试并创建了一个HelloWord project,按照提示一步一步设置完成后,发现要下载一些gradle resource,结果下载了一夜...
JUnit4引入了注解驱动的测试,比如`@Before`和`@After`,分别在每个测试方法执行前和执行后运行,通常用于初始化和清理资源。此外,`@BeforeClass`和`@AfterClass`则只在类级别的开始和结束时执行一次。 对于更复杂...
JUnit 是一个 Java 编程语言的单元测试框架。JUnit 在测试驱动的开发方面有很重要的发展,是起源于 JUnit 的一个统称为 xUnit 的单元测试框架之一。
《Junit 4.0 学习笔记》 JUnit 是一个广泛使用的Java编程语言的单元测试框架,尤其在敏捷开发和持续集成环境中扮演着至关重要的角色。本文将深入探讨JUnit 4.0版本的主要特性、核心概念以及如何有效利用它进行单元...
JUnit4基础文档 单元测试是软件测试的一种,旨在检验软件的正确性和可靠性。JUnit是一个流行的单元测试框架,广泛应用于Java开发中。本文档介绍了JUnit4的基础知识,包括单元测试的概念、JUnit4的HelloWorld示例、...
赠送jar包:junit-jupiter-api-5.5.2.jar; 赠送原API文档:junit-jupiter-api-5.5.2-javadoc.jar; 赠送源代码:junit-jupiter-api-5.5.2-sources.jar; 赠送Maven依赖信息文件:junit-jupiter-api-5.5.2.pom; ...
赠送jar包:junit-jupiter-engine-5.8.0-M1.jar; 赠送原API文档:junit-jupiter-engine-5.8.0-M1-javadoc.jar; 赠送源代码:junit-jupiter-engine-5.8.0-M1-sources.jar; 赠送Maven依赖信息文件:junit-jupiter-...
### JUnit4学习方法 #### 一、简介与背景 JUnit4是一款广泛应用于Java开发环境下的单元测试框架,它提供了一套简洁而强大的API来帮助开发者编写自动化测试代码。JUnit4相较于之前的版本,在语法和功能上都有显著...
这个“Junit学习.rar”压缩包显然包含了关于JUnit从3.8到4.9版本的学习资料,包括可能的操作手册、教程文档以及个人的学习笔记。以下是基于这些资源可能涵盖的一些关键知识点: 1. **JUnit基础知识**:了解JUnit的...