JUnit单元测试框架

认识JUnit

JUnit是一个用于Java编程语言的测试框架。它支持自动化单元测试,可以帮助开发人员测试代码的正确性和健壮性。JUnit提供了一组注解、断言和测试运行器,可以方便地编写和运行单元测试。
JUnit的使用步骤:

  1. 在项目中(pom.xml文件)添加JUnit依赖库
<dependency>
            <groupId>org.junit.jupitergroupId>
            <artifactId>junit-jupiter-apiartifactId>
            <version>5.9.2version>
        dependency>
        
        <dependency>
            <groupId>org.junit.jupitergroupId>
            <artifactId>junit-jupiter-paramsartifactId>
            <version>5.9.2version>
        dependency>
        
        <dependency>
            <groupId>org.junit.platformgroupId>
            <artifactId>junit-platform-suiteartifactId>
            <version>1.9.1version>
            <scope>testscope>
        dependency>
        
        <dependency>
            <groupId>org.junit.platformgroupId>
            <artifactId>junit-platform-suiteartifactId>
            <version>1.9.1version>
        dependency>
        
        <dependency>
            <groupId>org.junit.jupitergroupId>
            <artifactId>junit-jupiter-engineartifactId>
            <version>5.9.1version>
            <scope>testscope>
        dependency>
    dependencies>
  1. 创建测试类,在测试类中编写测试方法
  2. 使用JUnit提供的注解标记测试方法
  3. 在测试方法中使用JUnit提供的断言来验证代码的正确性
  4. 运行测试,查看测试结果

例如,以下是一个简单的JUnit测试类:

import org.junit.Test;
import static org.junit.Assert.*;

public class MyTest {
    @Test
    public void testAddition() {
        int result = 2 + 2;
        assertEquals(4, result);
    }
}

在这个例子中,我们使用了@Test注解标记了一个测试方法testAddition(),并在其中使用了assertEquals()断言来验证加法运算的正确性。如果测试失败,JUnit将输出错误信息并提示哪个断言失败了。

⭐️ 1. 注解

JUnit提供了多种注解,用于标记测试方法、初始化方法、清理方法等。常用的注解如下:

  1. @Test:标记一个测试方法。在JUnit中,所有的测试方法都必须使用@Test注解进行标记,以便JUnit运行器能够识别并执行这些方法。
  2. @Before:标记一个方法,在每个测试方法执行之前执行,用于初始化测试环境。@Before注解的方法通常用于初始化测试数据、创建对象等操作。
  3. @After:标记一个方法,在每个测试方法执行之后执行,用于清理测试环境。@After注解的方法通常用于释放资源、删除对象等操作。
  4. @BeforeClass:标记一个方法,在所有测试方法执行之前执行,通常用于初始化一些共享的资源。@BeforeClass注解的方法只会执行一次,并且必须是静态方法。
  5. @AfterClass:标记一个方法,在所有测试方法执行之后执行,通常用于清理共享资源。@AfterClass注解的方法只会执行一次,并且必须是静态方法。
  6. @Ignore:标记一个测试方法或测试类,表示该测试方法或测试类不参与测试。@Ignore注解的方法或类将被JUnit运行器忽略,不会执行。
  7. @RunWith:指定运行测试的运行器。@RunWith注解的值为一个运行器类,用于指定JUnit运行器的实现。例如,可以使用@RunWith(Parameterized.class)来运行参数化测试。

除了这些常用的注解外,JUnit还提供了其他一些注解,例如@Rule@ClassRule@Parameters等,可以根据需要使用这些注解来编写更加复杂的测试代码。
以下是一个使用这些常用测试方法的例子:

import org.junit.*;

public class MyTest {
    @Test
    public void testAddition() {
        int result = 2 + 2;
        assertEquals(4, result);
    }

   @BeforeAll
   static void SetUp(){
       System.out.println("执行BeforeAll");
   }

   //所有方法执行完后执行,只执行一次
   @AfterAll
   static void TearDown(){
       System.out.println("执行AfterAll");
   }

   //每执行一个测试方法前执行一次
   @BeforeEach
   void BeforE(){
       System.out.println("执行BeforeEach");
   }

   //每执行一个测试方法后执行一次
   @AfterEach
   void AfterE(){
       System.out.println("执行AfterEach");
   }

    @Test
    @Ignore
    public void testSomethingElse() {
        // 不参与测试的代码
    }
}

@Disabled注解和@Ignore注解

在JUnit中,@Disabled注解和@Ignore注解都可以用来标记测试方法或测试类,表示这些测试方法或测试类不需要参与测试。它们的作用是相同的,只是在JUnit的不同版本中有所差异。

在JUnit 4及以下版本中,使用@Ignore注解来标记测试方法或测试类。@Ignore注解有一个value参数,可以用来指定忽略测试的原因。例如:

import org.junit.Ignore;
import org.junit.Test;

@Ignore("这个测试方法尚未实现")
public class TestExample {

    @Test
    public void testMethod() {
        // 测试方法
    }
}

上面的示例中,使用@Ignore注解来标记testMethod()方法,指定测试方法尚未实现。

在JUnit 5及以上版本中,使用@Disabled注解来标记测试方法或测试类。@Disabled注解的作用与@Ignore注解相同,用于指定测试方法或测试类不需要参与测试。例如:

import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;

@Disabled("这个测试方法尚未实现")
public class TestExample {

    @Test
    public void testMethod() {
        // 测试方法
    }
}

上面的示例中,使用@Disabled注解来标记testMethod()方法,指定测试方法尚未实现。
需要注意的是,@Ignore注解和@Disabled注解都会将标记的测试方法或测试类从测试运行中排除,但是它们的语义略有不同。在JUnit 5及以上版本中,推荐使用@Disabled注解来标记测试方法或测试类。

⭐️2. 断言

JUnit提供了多种断言方法,用于验证代码的正确性。常用的断言方法如下:

  1. assertEquals(expected, actual):验证两个值是否相等。如果不相等,抛出AssertionError异常,并输出错误信息。
  2. assertTrue(condition):验证一个条件是否为真。如果条件为假,抛出AssertionError异常,并输出错误信息。
  3. assertFalse(condition):验证一个条件是否为假。如果条件为真,抛出AssertionError异常,并输出错误信息。
  4. assertNull(object):验证一个对象是否为null。如果对象不为null,抛出AssertionError异常,并输出错误信息。
  5. assertNotNull(object):验证一个对象是否不为null。如果对象为null,抛出AssertionError异常,并输出错误信息。
  6. assertSame(expected, actual):验证两个对象是否引用同一个对象。如果不是同一个对象,抛出AssertionError异常,并输出错误信息。
  7. assertNotSame(expected, actual):验证两个对象是否不引用同一个对象。如果是同一个对象,抛出AssertionError异常,并输出错误信息。

以下是一个使用断言的例子:

    @ParameterizedTest
    @ValueSource(strings = {"1"})
    void Test10(String num) {
        // 断言相等
        Assertions.assertEquals(num, "1");
        // 断言不相等
        Assertions.assertNotEquals(num, "11");
        // 断言为空
//        Assertions.assertNull(num);/
        // 断言不为空
        Assertions.assertNotNull(num);
    }

这些断言方法可以用于测试代码的各种情况,例如验证方法的返回值、验证方法是否抛出异常、验证对象的属性等等。在使用断言时,应该尽量使用具体的断言方法,并提供清晰明了的错误信息,以便于定位测试失败的原因。

⭐️ 3. 测试运行器

JUnit测试运行器是JUnit框架中的一个重要组件,用于执行测试用例、管理测试流程和输出测试结果。JUnit提供了多种测试运行器,可以根据不同的需求选择合适的运行器。

常用的JUnit测试运行器如下:

  1. JUnitCore:是JUnit框架中最基本的测试运行器,可以用来运行单个测试类或一组测试类。可以通过JUnitCore.runClasses(TestClass1.class,TestClass2.class)的方式来执行多个测试类。
  2. TextListener:是JUnit框架中内置的一个监听器,用于输出测试结果到控制台。可以通过JUnitCore.addListener(new TextListener())的方式注册TextListener监听器。
  3. JUnit4:是JUnit框架中默认的测试运行器,支持执行JUnit4风格的测试用例。可以使用@RunWith(JUnit4.class)注解来指定使用JUnit4运行器。
  4. Parameterized:是JUnit框架中的一个参数化测试运行器,可以用来执行多组参数的测试用例。可以使用@RunWith(Parameterized.class)注解来指定使用Parameterized运行器。
  5. Suite:是JUnit框架中的一个测试套件运行器,可以用来执行多个测试类或测试套件。可以使用@RunWith(Suite.class)注解来指定使用Suite运行器。
  6. Categories:是JUnit框架中的一个测试分类运行器,可以将测试用例按照不同的分类进行执行。可以使用@RunWith(Categories.class)注解来指定使用Categories运行器。

除了这些常用的测试运行器外,JUnit还提供了其他一些运行器,例如SpringJUnit4ClassRunnerPowerMockRunner等,用于支持其他框架或库的集成测试。在选择测试运行器时,应根据具体的需求选择合适的运行器。

使用Junit注释

⭐️ 参数

@ParameterizedTest: 注册参数
@ValueSource:单个参数
@CsvSource:多个参数
@CsvFileSource:文件参数
@MethodSource:方法参数

单个参数的注解

	@ParameterizedTest
    //ValueSource单参数
    @ValueSource(strings = {"1", "2", "3"})
    void Test06(String str) {
        System.out.println(str);
    }

多个参数的注解

	@ParameterizedTest
    //多参数,第一组,第二组
    @CsvSource({"1, 2", "3, 4"})
    void Test07(String str, int num) {
        System.out.println(str + " " + num);
    }

文件参数的注解

其中test01.scv文件放在resources中,其文件内容如下:
JUnit单元测试框架_第1张图片

	@ParameterizedTest
    //多参数,文件参数
    @CsvFileSource(resources = "test01.csv")
    void Test08(int id, String name) {
        System.out.println("id = " + id + ",name = " + name);
    }

方法参数的注解

	@ParameterizedTest
    // 注册的参数是什么
    @MethodSource("Generator")
    void Test09(String num, String name) {
    System.out.println(num + "" + name);
	}
	public static Stream<Arguments> Generator() {
        return Stream.of(Arguments.arguments("1, 小张", "2, 小李"));
    }

⭐️ 测试方法排序

JUnit 4及以上版本支持通过@Order注解对测试方法进行排序,以便按照指定的顺序执行测试方法。这个注解可以用于JUnit中的测试类和测试方法。

在JUnit测试类中,可以使用@TestMethodOrder注解来指定测试方法的执行顺序。@TestMethodOrder注解有一个value参数,用于指定测试方法的顺序。可以使用MethodOrderer.OrderAnnotation.class参数来使用@Order注解对测试方法进行排序。
注意:Order的数值越小,执行顺序越前
示例代码如下:

import org.junit.jupiter.api.*;

@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class TestOrderExample {

    @Test
    @Order(1)
    public void testMethod1() {
        // 测试方法1
    }

    @Test
    @Order(2)
    public void testMethod2() {
        // 测试方法2
    }

    @Test
    @Order(3)
    public void testMethod3() {
        // 测试方法3
    }
}

上面的示例中,使用@TestMethodOrder(MethodOrderer.OrderAnnotation.class)指定使用@Order注解对测试方法进行排序。在每个测试方法上,使用@Order注解指定测试方法的执行顺序。

除了使用@Order注解来对测试方法进行排序外,JUnit还提供了其他的测试方法排序方式,可以根据需要选择合适的排序方式。
常用的JUnit测试方法排序方式如下:

  1. MethodOrderer.Default:默认的测试方法排序方式,按照测试方法名称的字典顺序进行排序。
  2. MethodOrderer.Random:随机排序测试方法,每次执行测试时测试方法的顺序都会随机生成。
  3. MethodOrderer.Alphanumeric:按照测试方法名称的字母和数字顺序进行排序。
  4. MethodOrderer.OrderAnnotation:使用@Order注解对测试方法进行排序,可以自定义测试方法的执行顺序。
  5. MethodOrderer.DisplayName:按照测试方法的显示名称进行排序,可以通过@DisplayName注解指定测试方法的显示名称。
  6. MethodOrderer.MethodName:按照测试方法名称的字典顺序进行排序,与MethodOrderer.Default相同。

在JUnit 5中,可以使用@TestMethodOrder注解来指定测试方法排序方式。@TestMethodOrder注解有一个value参数,用于指定测试方法排序方式。
示例代码如下:

import org.junit.jupiter.api.*;

@TestMethodOrder(MethodOrderer.DisplayName.class)
public class TestOrderExample {

    @Test
    @DisplayName("测试方法1")
    public void testMethod1() {
        // 测试方法1
    }

    @Test
    @DisplayName("测试方法2")
    public void testMethod2() {
        // 测试方法2
    }

    @Test
    @DisplayName("测试方法3")
    public void testMethod3() {
        // 测试方法3
    }
}

上面的示例中,使用@TestMethodOrder(MethodOrderer.DisplayName.class)指定按照测试方法的显示名称进行排序。在每个测试方法上,使用@DisplayName注解指定测试方法的显示名称。
需要注意的是,测试方法的执行顺序应该尽量避免依赖关系,以保证测试方法的独立性和可重复性。

⭐️ Suite使用

在JUnit中,@Suite注解可以用来标记测试套件,用于执行多个测试类或测试方法。测试套件可以将多个相关的测试用例组合在一起,以便一次性执行这些测试用例。
使用@Suite注解时,需要将需要执行的测试类或测试方法作为参数传递给@Suite注解。可以使用@Suite.SuiteClasses注解来指定需要执行的测试类,也可以使用@SuiteClasses注解来指定需要执行的测试方法。

示例代码如下:

import org.junit.runner.RunWith;
import org.junit.runners.Suite;

@Suite
@Suite.SuiteClasses({TestClass1.class, TestClass2.class})
public class TestSuiteExample {
}

上面的示例中,使@Suite注解来标记TestSuiteExample类,指定需要执行TestClass1TestClass2两个测试类。在执行测试套件时,JUnit将依次执行TestClass1TestClass2中的所有测试方法。

在JUnit中,测试套件可以将多个相关的测试用例组合在一起,以便一次性执行这些测试用例。除了使用@Suite注解来标记测试套件外,JUnit还提供了其他的测试套件方式,例如使用@RunWith注解和自定义测试套件类。

  1. 使用@RunWith注解

在JUnit 4及以下版本中,可以使用@RunWith注解来指定测试运行器。可以创建一个自定义的测试运行器,来执行一组相关的测试用例。
示例代码如下:

import org.junit.runner.RunWith;
import org.junit.runners.Suite;

@RunWith(Suite.class)
@Suite.SuiteClasses({TestClass1.class, TestClass2.class})
public class TestSuiteExample {
}

上面的示例中,使用@RunWith(Suite.class)注解来指定测试运行器为Suite.class,表示需要执行一个测试套件。在测试套件中,使用@SuiteClasses注解来指定需要执行的测试类。

  1. 自定义测试套件类

在JUnit 5及以上版本中,可以创建一个实现TestTemplateTestTemplateInvocationContextProvider接口的自定义测试套件类,来执行一组相关的测试用例。
示例代码如下:

import org.junit.jupiter.api.TestTemplate;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.api.extension.ExtensionContext;

@ExtendWith(MyTestTemplateInvocationContextProvider.class)
public class TestSuiteExample {
    @TestTemplate
    public void testTemplate(String parameter) {
        // 测试模板方法
    }
}

class MyTestTemplateInvocationContextProvider implements TestTemplateInvocationContextProvider {
    @Override
    public boolean supportsTestTemplate(ExtensionContext context) {
        return true;
    }

    @Override
    public Stream<TestTemplateInvocationContext> provideTestTemplateInvocationContexts(ExtensionContext context) {
        // 返回测试模板上下文
    }
}

上面的示例中,创建了一个实现TestTemplate接口的测试套件类TestSuiteExample,并且使用@TestTemplate注解标记测试模板方法。同时,创建了一个实现TestTemplateInvocationContextProvider接口的测试模板上下文提供类MyTestTemplateInvocationContextProvider,用于提供测试模板上下文。在测试套件类中,使用@ExtendWith注解来指定测试模板上下文提供类。

数据驱动

Java数据驱动测试是一种测试方法,它可以通过提供一组测试数据,来自动化执行同一测试用例的多个不同数据集的测试。通过这种方法,可以提高测试的覆盖率和效率,同时减少手动测试的工作量。

在Java中,可以使用JUnit和TestNG等测试框架来实现数据驱动测试。下面以JUnit为例,介绍Java数据驱动测试的实现方法。

⭐️ 使用JUnit的Parameterized Runner

JUnit的Parameterized Runner可以用来执行数据驱动测试。Parameterized Runner的工作方式是,使用@Parameterized注解来标记测试类,将测试数据作为参数传递给测试方法,并对每组测试数据执行一次测试方法。

示例代码如下:

import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import java.util.Arrays;
import java.util.Collection;
import static org.junit.Assert.assertEquals;

@RunWith(Parameterized.class)
public class TestExample {
    private int input;
    private int expected;

    public TestExample(int input, int expected) {
        this.input = input;
        this.expected = expected;
    }

    @Parameterized.Parameters
    public static Collection<Object[]> testCases() {
        Object[][] cases = {
            {1, 2},
            {2, 4},
            {3, 6}
        };
        return Arrays.asList(cases);
    }

    @Test
    public void testMethod() {
        assertEquals(expected, input * 2);
    }
}

上面的示例中,使用@RunWith(Parameterized.class)注解来标记测试类,指定使用Parameterized Runner来执行数据驱动测试。在测试类中,使用@Parameterized.Parameters注解来标记测试数据提供方法,返回测试数据集合。每组测试数据作为构造函数的参数,用于初始化测试类中的成员变量。测试方法使用测试数据集合中的数据来执行测试。在测试结果中,每组测试数据都会产生一条测试结果。

⭐️ 使用JUnit的DataProvider

JUnit的DataProvider可以用来执行数据驱动测试。DataProvider的工作方式是,使用@DataProvider注解来标记测试数据提供方法,将测试数据作为参数传递给测试方法,并对每组测试数据执行一次测试方法。

示例代码如下:

import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import org.testng.annotations.DataProvider;
import static org.junit.Assert.assertEquals;

@RunWith(JUnit.class)
public class TestExample {
    @Test(dataProvider = "testCases")
    public void testMethod(int input, int expected) {
        assertEquals(expected, input * 2);
    }

    @DataProvider(name = "testCases")
    public static Object[][] testCases() {
        return new Object[][] {
            {1, 2},
            {2, 4},
            {3, 6}
        };
    }
}

上面的示例中,使用@Test(dataProvider = "testCases")注解来标记测试方法,并指定测试数据提供方法。测试数据提供方法使用@DataProvider(name = "testCases")注解来标记,返回测试数据集合。每组测试数据作为测试方法的参数,用于执行测试。在测试结果中,每组测试数据都会产生一条测试结果。

需要注意的是,数据驱动测试可以使用不同的测试数据集合来执行同一测试用例的多个不同数据集的测试。在测试过程中,需要确保测试数据的完整性和正确性,以避免数据驱动测试的误导性结果。另外,测试数据的质量和数量对测试结果的准确性和可靠性有很大影响,需要根据实际情况进行调整和优化。

你可能感兴趣的:(软件测试,junit,单元测试,java)