一、简介
这个估计大家都比我清楚了,JUnit是一个单元测试框架,我们可以基于它编写用来测试代码的代码,从而更方便地进行回归测试。
二、编写测试与断言(Assertion)
在Junit4中,编写一个测试方法只需要使用@Test注解并保证被注解的方法满足以下条件
- 方法可见性为public
- 方法无返回值
- 方法没有参数
在一个测试中,往往需要满足某种条件才能断定测试成功,而不仅仅是测试方法执行完毕,org.junit.Assert对象提供了各种断言方法,用于判定程序的执行结果是否符合预期,从而通过测试。
例如我们需要测试以下类的两个方法:
package org.haibin369.common; public class ObjectGenerator { public String getString(){ return "String"; } public Object getNull(){ return null; } }
我们需要编写以下的测试类和方法:
package org.haibin369.test; import org.haibin369.common.ObjectGenerator; import org.junit.Test; //静态导入,方便使用Assert对象的断言方法 import static org.junit.Assert.*; /** * 测试类,不需继承任何JUnit的类 */ public class ObjectGeneratorTest { //使用@Test标注测试方法 @Test public void testGetString() { ObjectGenerator generator = new ObjectGenerator(); String msg = generator.getString(); if (msg == null) { //Assert中也有使测试失败的fail方法,参数为失败信息(此处仅作演示) fail("Message is null"); } //断言得到的msg为AString,否则测试失败,第一个参数为失败时的信息 assertEquals("Wrong message generated.", "AString", msg); } @Test public void testGetNull() { ObjectGenerator generator = new ObjectGenerator(); //断言为空 assertNull("Returned object is not null", generator.getNull()); } }
执行以上测试,第二个测试会通过,而第一个会报错(org.junit.ComparisonFailure: Wrong message generated.),表明代码返回的结果和预期的不一样。
org.junit.Assert对象中还有很多断言方法,详情可参考API。
三、Before & After
现在有一个简单的登陆Action需要测试(User和ACLException代码比较简单,这里就不贴出来了)。
public class LoginAction { private static final User FORBIDDEN_USER = new User("admin", "admin"); private static final List<User> LOGIN_USER = new ArrayList<User>(); public void login(User user) throws ACLException, InterruptedException { if (FORBIDDEN_USER.equals(user)) { Thread.sleep(2000); throw new ACLException("Access Denied!"); } if (!LOGIN_USER.contains(user)) { LOGIN_USER.add(user); } } public void logout(User user) throws InterruptedException { LOGIN_USER.remove(user); } public List<User> getLoginUser() { return LOGIN_USER; } }
测试类很简单,如下:
public class LoginActionTest { @Test public void testLoginSuccess() throws Exception { LoginAction loginAction = new LoginAction(); User user = new User("haibin369", "123456"); loginAction.login(user); assertTrue("User didn't login!", loginAction.getLoginUser().contains(user)); } @Test public void testLogout() throws Exception { LoginAction loginAction = new LoginAction(); User user = new User("haibin369", "123456"); loginAction.login(user); loginAction.logout(user); assertFalse("User didn't logout!", loginAction.getLoginUser().contains(user)); } }
问题是这些测试中都有重复的代码去创建LoginAction,所以可以考虑把LoginAction作为成员变量,只初始化一次。同时为了避免测试方法间的影响,可以在每个测试执行完之后重置LoginAction的状态,即清空LOGIN_USER。在一般的测试中也许也会有类似的需求:在测试开始时打开一个文件,所有测试结束之后关闭这个文件。为了实现这种目的,JUnit提供了以下四个方法注解实现这种目的:
- @BeforeClass / @AfterClass:在所有测试方法执行之前 / 后执行,被注解的方法必须是public,static,无返回值,无参数;
- @Before / @After:在每个测试方法执行之前 / 后执行,被注解的方法必须是public,无返回值,无参数;
重写后的测试如下:
public class LoginActionTest { private static LoginAction loginAction; private static User user; @BeforeClass public static void init() { loginAction = new LoginAction(); user = new User("haibin369", "123456"); } @After public void clearLoginUser() { loginAction.getLoginUser().clear(); } @Test public void testLoginSuccess() throws Exception { loginAction.login(user); assertTrue("User didn't login!", loginAction.getLoginUser().contains(user)); } @Test public void testLogout() throws Exception { loginAction.login(user); loginAction.logout(user); assertFalse("User didn't logout!", loginAction.getLoginUser().contains(user)); } }
四、异常测试
在上面的LoginAction中,当使用Admin帐号登陆时,会抛出异常,这部分代码也需要测试,我们可以在@Test注解中配置期待异常,当测试抛出指定异常的时候则测试成功。
//当测试方法抛出ACLException时测试成功 @Test(expected = ACLException.class) public void testAdminLogin() throws ACLException, InterruptedException { loginAction.login(new User("admin", "admin")); }
上面的测试能测试出方法按照预期抛出异常,但是如果代码里面不只一个地方抛出ACLException(只是包含的信息不一样),我们还是无法分辨出来。这种情况可以使用JUnit的ExpectedException Rule来解决。
//使用@Rule标记ExpectedException @Rule public ExpectedException expectedException = ExpectedException.none(); @Test public void testAdminLogin2() throws ACLException, InterruptedException { //期待抛出ACLException expectedException.expect(ACLException.class); //期待抛出的异常信息中包含"Access Denied"字符串 expectedException.expectMessage(CoreMatchers.containsString("Access Denied")); //当然也可以直接传入字符串,表示期待的异常信息(完全匹配) //expectedException.expectMessage("Access Denied!"); loginAction.login(new User("admin", "admin")); }
五、超时测试
在JUnit中测试超时是使用@Test的timeout属性设置
//设置1000ms的超时时间,当超过这个时间测试还没执行完毕则失败 @Test(timeout = 1000) public void testLoginTimeout() throws Exception { loginAction.login(new User("admin", "admin")); }
也可以使用Timeout Rule设定全局的超时时间
//设置1000ms的超时时间,当超过这个时间测试还没执行完毕则失败 @Rule public Timeout timeout = new Timeout(1000); @Test public void testLoginTimeout() throws Exception { loginAction.login(new User("admin", "admin")); }
上面两个测试执行都会失败:java.lang.Exception: test timed out after 1000 milliseconds
六、忽略测试
使用@Ignore可以忽略一个测试
//忽略该测试,参数为输出信息 @Ignore("Temporary ignored as no changes.") @Test(timeout = 1000) public void testLoginTimeout() throws Exception { loginAction.login(new User("admin", "admin")); }
执行类里的所有测试,会输出一下信息,表示该测试被忽略了。
Test 'org.haibin369.test.LoginActionTest.testLoginTimeout' ignored (Temporary ignored as no changes.)
七、使用Suite执行多个测试类
现在我们有了ObjectGeneratorTest和LoginActionTest,如果需要一次过执行多个测试类的所有方法,可以使用@Suite与@Suite.SuiteClasses注解
//使用JUnit的Suite Runner执行测试 @RunWith(Suite.class) //配置所有需要执行的测试 @Suite.SuiteClasses({ ObjectGeneratorTest.class, LoginActionTest.class }) //创建一个类作为Test Suite的入口 public class MyTestSuite { }
相关推荐
### JUnit4学习笔记——入门篇 #### 一、配置MyEclipse在项目中引入JUnit4.jar包 在使用JUnit4进行单元测试之前,首先需要确保开发环境已正确配置JUnit库。对于使用MyEclipse IDE的开发者来说,可以通过以下步骤...
通过这份Junit学习笔记,你可以掌握单元测试的基本思想,熟练运用JUnit进行代码质量的保障。在实际开发中,单元测试不仅能帮助找出错误,还能在重构时提供安全保障,提高代码质量。不断学习和实践,你会发现自己在...
这个“Junit学习.rar”压缩包显然包含了关于JUnit从3.8到4.9版本的学习资料,包括可能的操作手册、教程文档以及个人的学习笔记。以下是基于这些资源可能涵盖的一些关键知识点: 1. **JUnit基础知识**:了解JUnit的...
总之,这个学习资源将带你深入理解JUnit的基本概念和高级特性,通过阅读`JUnit学习笔记.txt`并动手实践其中的示例,你将能熟练掌握如何利用JUnit3和JUnit4进行有效的单元测试,从而提升代码质量和项目稳定性。
在“JUnit4入门学习笔记.doc”这份文档中,我们可以期待找到以下关键知识点: 1. **JUnit介绍**:首先会介绍JUnit的基本概念,包括它的起源、目标以及在软件开发中的地位,以及与其它测试框架的比较。 2. **环境...
这篇入门笔记将带你深入了解JUnit的基本概念、使用方法以及其在实际开发中的应用。 **一、JUnit简介** JUnit是一个开源的、基于Java的测试框架,它简化了对代码进行单元测试的过程。通过JUnit,开发者可以快速地...
本文将深入探讨Eclipse插件开发的相关知识点,结合提供的"全书分为4篇共24章"的学习笔记和源码,帮助你更全面地理解和实践Eclipse插件开发。 第一篇:基础篇 在这一篇中,你将学习到Eclipse插件开发的基础知识,...
任务一:基于 JUnit 框架的覆盖率测试,学习如何使用 JUnit 框架来测试 Android 应用。 任务二:初探基于 JUnit 的 Android 测试框架,学习如何使用 JUnit 框架来测试 Android 应用。 任务三: Android 单元测试框架...
【Java学习笔记(源码)】是一份详细记录了Java编程语言学习过程的资源集合,包含实际的源代码示例。这份笔记旨在帮助初学者和有一定经验的开发者深入理解和掌握Java语言的核心概念、语法以及常见应用。以下是笔记中...
在《JAVA 学习笔记》中,良葛格深入浅出地讲解了Java编程语言的基础知识和进阶技巧,旨在帮助读者从零开始掌握这一广泛应用于企业级开发的重要语言。以下是该学习笔记中可能涵盖的一些核心知识点: 1. **Java基础...
林信良的Java学习笔记是一份珍贵的学习资源,尤其对于编程初学者和具有一定开发经验的程序员。这份笔记不仅详细阐述了Java编程语言的核心概念,而且还包括了深入的高级特性,从而为不同层次的读者提供了全面的学习...
### Java学习笔记要点 #### 一、了解Java ##### 1.1 Java的起源与发展历程 - **起源**: Java 最初是由 Sun 公司在 Green Project 中为了开发 Star7 应用程序而创建的一种编程语言。 - **命名**: 语言的名字来源于 ...
19. **Android Jetpack**:一组可复用的组件,包括Architecture Components、Lifecycle、Room等,帮助构建更稳定、更易维护的应用。 20. **Android KTX**:Kotlin扩展库,提供简洁的API,简化Android开发。 通过...
【安卓学习笔记】是作者GcsSloop在学习Android开发过程中的个人心得和问题解决方案的集合,旨在帮助读者深入理解Android系统以及应用开发。这份笔记不仅涵盖了基础概念,还可能包含高级特性和最佳实践,是Android...
- **junit**:一个常用的单元测试框架。 ### 二、数据库访问 #### Spring JDBC 模块 - **spring-jdbc**:提供了对 JDBC 的封装,使得数据访问更加简单且错误更少。 #### Spring ORM 模块 - **spring-orm**:支持...
- `提纲.doc`可能包含对JUnit学习的结构化大纲,帮助系统学习。 - `testingandroid-090828164936-phpapp02.pdf`可能是关于Android测试的详细指南,可能涵盖JUnit在Android开发中的实践。 - `Fibonacci.pdf`可能...
这份"java校招学习笔记"应该是一个全面的参考资料,帮助求职者巩固Java知识,提高解决问题的能力,以应对面试中的各种挑战。同时,实践项目经验和解决实际问题的能力也是校招面试中不可或缺的部分,因此理论学习的...
### Java+JDK6学习笔记知识点详解 #### 一、Java简介 - **起源与历史:** - 最初由Sun公司的Green Project发起,旨在创建一个名为Star7的应用程序编程语言。 - 名称来源于创始人James Gosling窗外的一棵橡树...
这个"Android_学习笔记.zip"文件很可能包含了一个详细的Android开发学习路径和关键知识点的总结。下面将基于这个主题,详细讲解Android开发的一些核心概念和技术。 首先,Android是Google开发的一款开源操作系统,...
### Java李兴华学习笔记之Java常用类库 #### 一、课程介绍及知识点概览 根据提供的资料,“Java李兴华学习笔记之Java常用类库”这份文档来源于北京MLDN软件实训中心的教学资料,主要涵盖了Java编程语言中常用类库...