[JUnit] 基于JUnit从零开始认识单元测试

@TOC

手机用户请横屏获取最佳阅读体验,REFERENCES中是本文参考的链接,如需要链接和更多资源,可以关注其他博客发布地址。

平台 地址
CSDN https://blog.csdn.net/sinat_28690417
简书 https://www.jianshu.com/u/3032cc862300
个人博客 https://yiyuery.club

基于JUnit从零开始认识单元测试

JUnit预备知识

什么是软件测试?

  • 软件测试是检查实际结果与预期结果是否匹配并确保软件系统无缺陷的活动。
  • 软件测试还有助于识别产品与实际需求不符或是缺失项。
  • 测试活动既可以手动完成,也可以使用自动化工具完成。
  • 有些人更喜欢将软件测试称为白盒和黑盒测试

什么是软件测试目标?

  • 在给定的产品中尽可能多地发现错误(或bug)。
  • 演示一个给定的软件产品与它的需求规格匹配。
  • 使用最小的成本和努力来验证软件的质量。
  • 生成高质量的测试用例,执行有效的测试,并发布正确和有用的问题报告。

什么是软件测试过程?

软件测试通常分为两个主要过程——验证 & 认证。

  • 验证是当您的团队只需要检查软件、系统或框架是否符合文档要求时的过程。

  • 认证是您的团队需要验证系统正确性的过程。在这个过程中,您将回顾产品、系统,并考虑用户真正想要什么和已经做了什么。

在软件测试中,缺陷和错误之间有区别,我们应该清楚地区分,以避免误解问题。

软件测试分类

.

单元测试这是在开发人员级别使用的最基本的测试,测试人员专注于单元代码的单个部分,而它已经从任何外部交互或依赖于任何模块之前被隔离。这个测试要求开发人员检查他们编写的最小代码单元,并证明单元可以独立工作。

如果你听说过测试驱动开发(TDD:Test-Driven Development),单元测试就不陌生。单元测试是用来对一个模块、一个函数或者一个类来进行正确性检验的测试工作。比如对函数abs(),我们可以编写出以下几个测试用例:

  • 输入正数,比如1、1.2、0.99,期待返回值与输入相同;
  • 输入负数,比如-1、-1.2、-0.99,期待返回值与输入相反;
  • 输入0,期待返回0;
  • 输入非数值类型,比如None、[]、{},期待抛出TypeError。

把上面的测试用例放到一个测试模块里,就是一个完整的单元测试。单元测试通过后有什么意义呢?

如果单元测试通过,说明我们测试的这个函数能够正常工作。如果单元测试不通过,要么函数有bug,要么测试条件
输入不正确,总之,需要修复使单元测试能够通过。

如果我们对abs()函数代码做了修改,只需要再跑一遍单元测试,如果通过,说明我们的修改不会对abs()函数原有
的行为造成影响,如果测试不通过,说明我们的修改与原有行为不一致,要么修改代码,要么修改测试。

这种以测试为驱动的开发模式最大的好处就是确保一个程序模块的行为符合我们设计的测试用例。在将来修改的
时候,可以极大程度地保证该模块行为仍然是正确的。

From: 廖雪峰

单元测试方式

单元测试可以由两种方式完成:

  • 人工测试

    • 手动执行测试用例并不借助任何工具的测试被称为人工测试。�消耗时间并单调:由于测试用例是由人力资源执行,所以非常缓慢并乏味。
    • 人力资源上投资巨大:由于测试用例需要人工执行,所以在人工测试上需要更多的试验员。
    • 可信度较低:人工测试可信度较低是可能由于人工错误导致测试运行时不够精确。
    • 非程式化:编写复杂并可以获取隐藏的信息的测试的话,这样的程序无法编写。
  • 自动测试(借助工具支持并且利用自动工具执行用例被称为自动测试。)

    • 快速自动化运行测试用例时明显比人力资源快。
    • 人力资源投资较少:测试用例由自动工具执行,所以在自动测试中需要较少的试验员。
    • 可信度更高:自动化测试每次运行时精确地执行相同的操作。
    • 程式化:试验员可以编写复杂的测试来显示隐藏信息。

JUnit 简介

JUnit 是一个 Java 编程语言的单元测试框架。JUnit 在测试驱动的开发方面有很重要的发展,是起源于 JUnit 的一个统称为 xUnit 的单元测试框架之一。

JUnit 促进了先测试后编码的理念,强调建立测试数据的一段代码,可以先测试,然后再应用。这个方法就好比“测试一点,编码一点,测试一点,编码一点……”,增加了程序员的产量和程序的稳定性,可以减少程序员的压力和花费在排错上的时间。

特点

  • JUnit 是一个开放的资源框架,用于编写和运行测试。
  • 提供注释来识别测试方法。
  • 提供断言来测试预期结果。
  • 提供测试运行来运行测试。
  • JUnit 测试允许你编写代码更快,并能提高质量。
  • JUnit 优雅简洁。没那么复杂,花费时间较少。
  • JUnit 测试可以自动运行并且检查自身结果并提供即时反馈。所以也没有必要人工梳理测试结果的报告。
  • JUnit 测试可以被组织为测试套件,包含测试用例,甚至其他的测试套件。
  • JUnit 在一个条中显示进度。如果运行良好则是绿色;如果运行失败,则变成红色。

从零开始搭建JUnit测试环境

测试场景

JUnit是一款优秀的开源Java单元测试框架,也是目前使用率最高最流行的测试框架,开发工具Eclipse和IDEA对JUnit都有很好的支持,JUnit主要用于以下测试场景。

  • 白盒测试:把测试对象看作一个打开的盒子,程序内部的逻辑结构和其他信息对测试人�员是公开的;
  • 回归测试:软件或环境修复或更正后的再测试;
  • 单元测试:最小粒度的测试,以测试某个功能或代码块。一般由程序员来做,因为它需要知道内部程序设计和编码的细节;

JUnit GitHub地址:https://github.com/junit-team

环境搭建

  • Spring Boot 2.1.0 RELEASE
  • JUnit 4.12
  • Maven 3.0.0+
  • IDEA 2019.2
testImplementation 'org.springframework.boot:spring-boot-starter-test'
.

Spring 框架

.

Spring Boot 框架

.
.

核心API

JUnit API TestCase

测试样例定义了运行多重测试的固定格式

  • int countTestCases() 为被run(TestResult result) 执行的测试案例计数
  • TestResult createResult() 创建一个默认的 TestResult 对象
  • String getName() 获取 TestCase 的名称
  • TestResult run() 一个运行这个测试的方便的方法,收集由TestResult 对象产生的结果
  • void run(TestResult result) 在 TestResult 中运行测试案例并收集结果
  • void setName(String name) 设置 TestCase 的名称
  • void setUp()
    创建固定装置,例如,打开一个网络连接
  • void tearDown() 拆除固定装置,例如,关闭一个网络连接
  • String toString() 返回测试案例的一个字符串表示
/*测试入口*/
public class Ex3Test {

    public static void main(String[] args) {
        Result result = JUnitCore.runClasses(JunitEx3Test.class,JunitEx3_2Test.class);
        for (Failure failure : result.getFailures()) {
            System.out.println(failure.toString());
        }
        System.out.println(result.wasSuccessful());
    }

}
public class JunitEx3_2Test extends TestCase {


    @Test
    public void testXX2() {
        System.out.println("No of Test2 Case:" + this.countTestCases());
        System.out.println("Original Test Name:" + this.getName());
        this.setName("JunitEx3_2Test Name");
        System.out.println("Update Test Name:" + this.getName());
    }
}

public class JunitEx3Test extends TestCase {

    /**
     * 为被run(TestResult result) 执行的测试案例计数
     * 注意前缀必须为test***
     */
    @Test
    public void testX1() {
        System.out.println("No of Test Case:" + this.countTestCases());
        System.out.println("Original Test Name:" + this.getName());
        this.setName("testX1 Name");
        System.out.println("Update Test Name:" + this.getName());
    }

    @Test
    public void testX2() {
        System.out.println("No of Test Case:" + this.countTestCases());
        System.out.println("Original Test Name:" + this.getName());
        this.setName("testX2 Name");
        System.out.println("Update Test Name:" + this.getName());
    }
}

JUnit API TestResult

TestResult 类收集所有执行测试案例的结果。它是收集参数层面的一个实例。这个实验框架区分失败和错误。失败是可以预料的并且可以通过假设来检查。错误是不可预料的问题就像 ArrayIndexOutOfBoundsException。

TestResult 类的一些重要方法列式如下:

  • void addError(Test test, Throwable t) 在错误列表中加入一个错误
  • void addFailure(Test test, AssertionFailedError t) 在失败列表中加入一个失败
  • void endTest(Test test) 显示测试被编译的这个结果
  • int errorCount() 获取被检测出错误的数量
  • Enumeration errors() 返回错误的详细信息
  • int failureCount() 获取被检测出的失败的数量
  • void run(TestCase test) 运行 TestCase
  • int int runCount() 获得运行测试的数量
  • void startTest(Test test) 声明一个测试即将开始
  • void stop()标明测试必须停止
/*测试入口*/
public class Ex4Test {

    public static void main(String[] args) {
        Result result = JUnitCore.runClasses(JEx4_1Test.class);
        for (Failure failure : result.getFailures()) {
            System.out.println(failure.toString());
        }
        System.out.println(result.wasSuccessful());
    }
}

public class JEx4_1Test extends TestResult {

    @Test
    public void testX1() throws IllegalArgumentException {
        throw new IllegalArgumentException("testX1 failed");
    }
    @Test
    public void testX2() throws IllegalArgumentException {
        throw new IllegalArgumentException("testX2 failed");
    }

    @Test
    public void testX3()  {
        System.out.println("testX3 success...");
    }
}

JUnit API TestSuite

TestSuite 类是测试的组成部分。它运行了很多的测试案例

  • void addTest(Test test) 在套中加入测试。
  • void addTestSuite(Class<? extends TestCase> testClass) 将已经给定的类中的测试加到套中。
  • int countTestCases() 对这个测试即将运行的测试案例进行计数。
  • String getName() 返回套的名称。
  • void run(TestResult result) 在 TestResult 中运行测试并收集结果。
  • void setName(String name) 设置套的名称。
  • Test testAt(int index) 在给定的目录中返回测试。
  • int testCount() 返回套中测试的数量。
  • static Test warning(String message) 返回会失败的测试并且记录警告信息。
/*测试入口*/
public class Ex5Test {

    public static void main(String[] args) {
        TestSuite suite = new TestSuite(TestJunit1.class, TestJunit2.class);
        TestResult result = new TestResult();
        suite.run(result);
        System.out.println("Number of test cases = " + result.runCount());
    }
}

public class TestJunit1 extends TestCase {

    String message = "Robert";
    MessageUtil messageUtil = new MessageUtil(message);

    @Test
    public void testMessage() {
        System.out.println("TestJunit1 testMessage()");
        assertEquals(message, messageUtil.printMessage());
    }
}

public class TestJunit2 extends TestCase {

    String message = "Robert";
    MessageUtil messageUtil = new MessageUtil(message);

    @Test
    public void testMessage() {
        System.out.println("TestJunit2 testMessage()");
        message = "Hi!" + "Robert";
        assertEquals(message,messageUtil.printMessage());
    }
}

JUnit单元测试如何开展

IDEA支持

IntellJ IDEA 支持快速生成测试用例

Ctrl + Shift + T

.
.

断言测试

测试结果的表达式

断言测试也就是期望值测试,是单元测试的核心,也就是决定测试结果的表达式

Assert对象中的断言方法:
Assert.assertEquals 对比两个值相等
Assert.assertNotEquals 对比两个值不相等
Assert.assertSame 对比两个对象的引用相等
Assert.assertArrayEquals 对比两个数组相等
Assert.assertTrue 验证返回是否为真
Assert.assertFlase 验证返回是否为假
Assert.assertNull 验证null
Assert.assertNotNull 验证非null
public class Ex1Test {

    public static void main(String[] args) {
        Result result = JUnitCore.runClasses(Ex1Test.class);
        for (Failure failure : result.getFailures()) {
            System.out.println(failure.toString());
        }
        System.out.println(result.wasSuccessful());
    }

    /**
     * 简单输出测试 Person(name=xxx)
     */
    @Test
    public void test1() {
        Person person = Person.builder().name("xxx").build();
        System.out.println(person.toString());
    }

    /**
     * 利用 Assert 断言输出结果
     * org.junit.Assert
     */
    @Test
    public void test2() {
        Person person = Person.builder().name("xxx").build();
        System.out.println(person.toString());
        Assert.assertEquals(person.getName(), "xxx");
        Assert.assertSame(person.getName(), "xxx");
        Assert.assertNotSame(person.getName(), "xx2");
        Assert.assertFalse(person.getName().endsWith("xx2"));
        Assert.assertTrue(person.getName().endsWith("xx"));
        Assert.assertNull(null);
        Assert.assertNotNull(person);
    }

    /**
     * 测试  @Before
     * Person(name=before....1)
     * Person(name=xxx3)
     */
    @Test
    public void test3() {
        Person person = Person.builder().name("xxx3").build();
        System.out.println(person.toString());
    }

    @Before
    public void before1() {
        Person person = Person.builder().name("before....1").build();
        System.out.println(person.toString());
    }

    /**
     * 测试 @After
     * Person(name=before....1)
     * Person(name=xxx4)
     * Person(name=after...1)
     */
    @Test
    public void test4() {
        Person person = Person.builder().name("xxx4").build();
        System.out.println(person.toString());
    }

    @After
    public void after1() {
        Person person = Person.builder().name("after...1").build();
        System.out.println(person.toString());
    }

    /**
     * 测试@AfterClass
     * Person(name=before....1)
     * Person(name=xxx5)
     * Person(name=after...1)
     * Person(name=after...2)
     */
    @Test
    public void test5() {
        Person person = Person.builder().name("xxx5").build();
        System.out.println(person.toString());
    }

    /**
     * java.lang.Exception: Method after2() should be static
     * 在所有方法执行之后执行
     */
    @AfterClass
    public static void after2() {
        Person person = Person.builder().name("after...2").build();
        System.out.println(person.toString());
    }

    /**
     * 测试 @BeforeClass
     * Person(name=before...2)
     * Person(name=before....1)
     * Person(name=xxx6)
     * Person(name=after...1)
     * Person(name=after...2)
     */
    @Test
    public void test6() {
        Person person = Person.builder().name("xxx6").build();
        System.out.println(person.toString());
    }

    /**
     * java.lang.Exception: Method before2() should be static
     * 在所有方法执行之前执行
     */
    @BeforeClass
    public static void before2() {
        Person person = Person.builder().name("before...2").build();
        System.out.println(person.toString());
    }

    /**
     * hamcrest-core-1.3.jar
     * Hamcrest是一款用以编写matcher对象的框架,以类库的形式发布。一个matcher对象就是一个明确定义的匹配规则.
     * > 匹配规则:Matchers
     */
    @Test
    @Ignore
    public void test7() {
        MatcherAssert.assertThat(Long.valueOf(1), instanceOf(Integer.class));
        //字符串匹配符
        String n = "Magci";
        //containsString:字符串变量中包含指定字符串时,测试通过
        MatcherAssert.assertThat(n, Matchers.containsString("ci"));
        //startsWith:字符串变量以指定字符串开头时,测试通过
        MatcherAssert.assertThat(n, Matchers.startsWith("Ma"));
        //endsWith:字符串变量以指定字符串结尾时,测试通过
        MatcherAssert.assertThat(n, Matchers.endsWith("i"));
        //euqalTo:字符串变量等于指定字符串时,测试通过
        MatcherAssert.assertThat(n, Matchers.equalTo("Magci"));
        //equalToIgnoringCase:字符串变量在忽略大小写的情况下等于指定字符串时,测试通过
        MatcherAssert.assertThat(n, Matchers.equalToIgnoringCase("magci"));
        //equalToIgnoringWhiteSpace:字符串变量在忽略头尾任意空格的情况下等于指定字符串时,测试通过
        MatcherAssert.assertThat(n, Matchers.equalToIgnoringWhiteSpace(" Magci   "));
        //...so on
    }

    @Test
    public void testX() {

    }

    /**
     * fail({{message}}) 直接中止方法运行
     */
    @Test
    @Ignore
    public void test8() {
        Assert.fail("directlly stop and output fail log!");
    }
}

套件测试

测试套件意味着捆绑几个单元测试用例并且一起执行他们。在 JUnit 中,@RunWith 和 @Suite 注释用来运行套件测试。这个教程将向您展示一个例子,其中含有两个测试样例 TestJunit1 & TestJunit2 类,我们将使用测试套件一起运行他们。

.
/*测试入口*/
public class Ex2Test{

    public static void main(String[] args) {
        Result result = JUnitCore.runClasses(TestSuite.class);
        for (Failure failure : result.getFailures()) {
            System.out.println(failure.toString());
        }
        System.out.println(result.wasSuccessful());
    }

}

public class MessageUtil {

    String message;

    public String printMessage() {
        return message;
    }

    public MessageUtil(String message) {
        this.message = message;
    }
}

public class TestJunit1 {

    String message = "Robert";
    MessageUtil messageUtil = new MessageUtil(message);

    @Test
    public void testMessage() {
        System.out.println("TestJunit1 testMessage()");
        assertEquals(message, messageUtil.printMessage());
    }
}

public class TestJunit2 {

    String message = "Robert";
    MessageUtil messageUtil = new MessageUtil(message);

    @Test
    public void testMessage() {
        System.out.println("TestJunit2 testMessage()");
        message = "Hi!" + "Robert";
        assertEquals(message,messageUtil.printMessage());
    }
}

@RunWith(Suite.class)
@Suite.SuiteClasses({
        TestJunit1.class ,TestJunit2.class
})
public class TestSuite {
}

时间测试

Junit 提供了一个暂停的方便选项。如果一个测试用例比起指定的毫秒数花费了更多的时间,那么 Junit 将自动将它标记为失败。timeout 参数和 @Test 注释一起使用。现在让我们看看活动中的 @test(timeout)。

.
public class Ex6Test {

    public static void main(String[] args) {
        Result result = JUnitCore.runClasses(JEx6_1Test.class);
        for (Failure failure : result.getFailures()) {
            System.out.println(failure.toString());
        }
        System.out.println(result.wasSuccessful());
    }
}

public class JEx6_1Test {

    @Test
    public void testX1(){
        System.out.println("x1");
    }

    @Test(timeout = 10)
    public void testX2(){
        for(int i =0;i<100000000;i++){
            Math.random();
        }
        System.out.println("x2");
    }

    @Test
    public void testX3(){
        System.out.println("x3");
    }
}

异常测试

Junit 用代码处理提供了一个追踪异常的选项。你可以测试代码是否它抛出了想要得到的异常。expected 参数和 @Test 注释一起使用。现在让我们看看活动中的 @Test(expected)。

.
/*测试入口*/
public class Ex7Test {

    public static void main(String[] args) {
        Result result = JUnitCore.runClasses(JEx7_1Test.class);
        for (Failure failure : result.getFailures()) {
            System.out.println(failure.toString());
        }
        System.out.println(result.wasSuccessful());
    }
}
public class JEx7_1Test {

    String message = "Robert";
    MessageUtil messageUtil = new MessageUtil(message);

    @Test
    public void testX1(){
        System.out.println("x1");
    }

    //@Test(expected = ArithmeticException.class)
    @Test(expected = IllegalArgumentException.class)
    public void testX2(){
        messageUtil.printMessage();
    }

    @Test
    public void testX3(){
        System.out.println("x3");
    }
}

class MessageUtil {

    private String message;

    //Constructor
    //@param message to be printed
    public MessageUtil(String message){
        this.message = message;
    }

    // prints the message
    public void printMessage(){
        System.out.println(message);
        int a =0;
        int b = 1/a;
    }

    // add "Hi!" to the message
    public String salutationMessage(){
        message = "Hi!" + message;
        System.out.println(message);
        return message;
    }
}

参数化测试

Junit 4 引入了一个新的功能参数化测试。参数化测试允许开发人员使用不同的值反复运行同一个测试。你将遵循 5 个步骤来创建参数化测试。

  • 用 @RunWith(Parameterized.class) 来注释 test 类。
  • 创建一个由 @Parameters 注释的公共的静态方法,它返回一个对象的集合(数组)来作为测试数据集合。
  • 创建一个公共的构造函数,它接受和一行测试数据相等同的东西。
  • 为每一列测试数据创建一个实例变量。
  • 用实例变量作为测试数据的来源来创建你的测试用例。

一旦每一行数据出现测试用例将被调用。

/*测试入口*/
public class Ex8Test {

    public static void main(String[] args) {
        Result result = JUnitCore.runClasses(JEx8_1Test.class);
        for (Failure failure : result.getFailures()) {
            System.out.println(failure.toString());
        }
        System.out.println(result.wasSuccessful());
    }
}
@RunWith(Parameterized.class)
public class JEx8_1Test {
    private Integer inputNumber;
    private Boolean expectedResult;
    private PrimeNumberChecker primeNumberChecker;

    @Before
    public void initialize() {
        primeNumberChecker = new PrimeNumberChecker();
    }

    public JEx8_1Test(Integer inputNumber,
                                  Boolean expectedResult) {
        this.inputNumber = inputNumber;
        this.expectedResult = expectedResult;
    }

    @Parameterized.Parameters
    public static Collection primeNumbers() {
        return Arrays.asList(new Object[][] {
                { 2, true },
                { 6, false },
                { 19, true },
                { 22, false },
                { 23, true }
        });
    }

    @Test
    public void testPrimeNumberChecker() {
        System.out.println("Parameterized Number is : " + inputNumber);
        assertEquals(expectedResult,
                primeNumberChecker.validate(inputNumber));
    }
}

/**
 * 质数
 */
class PrimeNumberChecker {
    public Boolean validate(final Integer primeNumber) {
        for (int i = 2; i < (primeNumber / 2); i++) {
            if (primeNumber % i == 0) {
                return false;
            }
        }
        return true;
    }
}

事务控制

.
.
public class Ex1Test extends BaseBootJunitTest {

    @Resource
    private IPersonService personService;

    /**
     * 初始数据插入
     */
    @Test
    public void testX1() {
        personService.saveWithName("p_test_1111");
    }


    /**
     * 方法内部事务间隔离
     */
    @Test
    public void testX2() {
        //第一行数据插入成功
        personService.saveWithName(CapsuleStringUtil.randomStr("p_test_"));
        //第二行数据插入失败
        personService.saveNoTransactional("p_test_1111");
    }

    /**
     * 针对Test方法加入事务控制
     * 避免测试数据污染数据库
     */
    @Test
    @Transactional(rollbackFor = Exception.class)
    public void testX3() {
        //第一行数据插入失败
        personService.saveWithName(CapsuleStringUtil.randomStr("p_test_"));
        //第二行数据插入失败
        personService.saveNoTransactional("p_test_1111");
    }
}

接口测试

.
.
public class Ex2Test extends BaseBootJunitTest {

    @Resource
    private TestRestTemplate restTemplate;

    @Test
    public void testHello() {
        String resp = restTemplate.getForObject("/hello", String.class);
        System.out.println(resp);
        Assert.assertEquals("Hello Junit!", resp);
    }
}

忽略测试

.

.

框架扩展

Hamcrest匹配器的用法

.

官网地址 http://hamcrest.org/JavaHamcrest/tutorial

.
.

自动化测试

.

/*测试入口*/
public class Ex3Test {

    public static void main(String[] args) {
        Result result = JUnitCore.runClasses(JEx3_1Test.class);
        for (Failure failure : result.getFailures()) {
            System.out.println(failure.toString());
        }
        System.out.println(result.wasSuccessful());
    }
}

@FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class JEx3_1Test extends BaseBootJunitTest {

    @Resource
    private IPersonService personService;

    private String pName;

    /**
     * 每个测试方法都是个测试用例,独立执行 @beforeInit 注解标注的方法
     */
    @Before
    public void before() {
        System.out.println("[Before]-----------------------------------");
        pName = "p_test_auto_1";
    }

    @After
    public void after() {
        System.out.println("[After]-----------------------------------");
    }

    /**
     * 正常过程:人员添加
     */
    @Test
    public void testX() {
        Person person = personService.saveWithName(pName);
        log("添加后人员信息返回结果", person);
        Person dbPerson = personService.findByPersonName(pName,true);
        Assert.assertNotNull(dbPerson);
    }

    /**
     * 正常过程:人员修改
     */
    @Test
    public void testX2() {
        Person oldPerson = personService.findByPersonName(pName,true);
        oldPerson.setName(pName + "_modify");
        Person newPerson = personService.saveWithResult(oldPerson);
        log("修改后人员信息", newPerson);
        Assert.assertNotNull(newPerson);
        Assert.assertEquals(oldPerson.getName(), newPerson.getName());
    }

    /**
     * 正常过程:人员删除
     */
    @Test
    public void testX3() {
        Person dbPerson = personService.findByPersonName(pName+"_modify",true);
        personService.delete(dbPerson.getId());
        log("删除前人员信息", dbPerson);
        Person personDel = personService.findByPersonName(dbPerson.getName(), false);
        log("删除后搜索结果", personDel);
    }
}

总结

本文从软件测试为讨论的切入点,介绍了单元测试在软件测试中的重要性和对应角色。接下来,以JUnit测试框架展开,就环境搭建、测试类型、JUnit 核心API、JUnit各种测试方法分别进行了介绍,并提供了代码示例。最后,结合人员的增删改操作,编写了对应的自动化测试用例。

REFRENCES

更多

扫码关注“架构探险之道”,回复本文标题或关键词,获取本文源码

.

知识星球(扫码加入获取历史源码和文章资源链接)

.
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,723评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,080评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,604评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,440评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,431评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,499评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,893评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,541评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,751评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,547评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,619评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,320评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,890评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,896评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,137评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,796评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,335评论 2 342