51Testing软件测试论坛

 找回密码
 (注-册)加入51Testing

QQ登录

只需一步,快速开始

微信登录,快人一步

手机号码,快捷登录

查看: 3578|回复: 0
打印 上一主题 下一主题

[原创] 基于JUnit5框架的Java单元测试流程

[复制链接]
  • TA的每日心情
    无聊
    3 天前
  • 签到天数: 1050 天

    连续签到: 1 天

    [LV.10]测试总司令

    跳转到指定楼层
    1#
    发表于 2020-12-7 11:20:54 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
     1.原理图

    2. 基本架构
      被测代码
    1. package com.jerry;

    2.   public class Calculator{

    3.       private static int result;

    4.       public void add(int n) {

    5.           result = result + n;

    6.       }

    7.       public void substract(int n) {

    8.           result = result - n;  

    9.       }

    10.       public void multiply(int n) {

    11.           result = result * n;

    12.       }

    13.       public void divide(int n){

    14.           try {

    15.               result = result / n;

    16.           }catch(ArithmeticException ex){

    17.               System.out.println(ex);

    18.               throw new ArithmeticException("The n not allowed to 0!!")

    19.           }

    20.   }

    21.   }
    复制代码
    最基本的测试代码
    1. public class CalculatorTest {

    2.       private static Calculator calculator = new Calculator();

    3.       @BeforeEach

    4.       public void setUp() throws Exception {

    5.           calculator.clear();

    6.       }

    7.       @Test

    8.       @DisplayName("测试加法")

    9.       public void testAdd() {

    10.           calculator.add(2);

    11.           calculator.add(3);

    12.           assertEquals(5, calculator.getResult());

    13.       }

    14.       @Test

    15.       @DisplayName("测试减法")

    16.       public void testSubstract() {

    17.           calculator.add(5);

    18.   calculator.substract(3);

    19.           Assertions.assertEquals(2, calculator.getResult());

    20.       }

    21.       @Test

    22.       @DisplayName("测试乘法")

    23.       public void testMultiply() {

    24.           calculator.add(3);

    25.           calculator.multiply(2);

    26.           Assertions.assertEquals(6, calculator.getResult());

    27.       }

    28.       @Test

    29.       @DisplayName("测试除法")

    30.       public void testDivide() {

    31.           calculator.add(9);

    32.           calculator.divide(3);

    33.           Assertions.assertEquals(3, calculator.getResult());

    34.       }
    复制代码
    标签@DisplayName可以在测试结果的时候显示其内容。

    3.JUnit5的修饰符

    描述装饰符的程序
    1.  package com.jerry;

    2.   import static org.junit.jupiter.api.Assertions.assertAll;

    3.   import org.junit.jupiter.api.*;

    4.   public class MyFirstJunit5Test {

    5.   @BeforeAll

    6.       @DisplayName("每条用例开始时执行")

    7.   public static void startALL(){

    8.   System.out.println("BeforeAll");

    9.       }

    10.   

    11.   @AfterAll

    12.       @DisplayName("每条用例开始时执行")

    13.   public static void endAll(){

    14.   System.out.println("AfterAll");

    15.       }

    16.   

    17.   @BeforeEach

    18.       @DisplayName("每条用例开始时执行")

    19.       void start(){

    20.   System.out.println("BeforeEach");

    21.       }

    22.       @AfterEach

    23.       @DisplayName("每条用例结束时执行")

    24.       void end(){

    25.       System.out.println("AfterEach");

    26.       }

    27.       @Test

    28.       void myFirstTest() {

    29.       System.out.println("myFirstTest");

    30.       Assertions.assertEquals(2, 1 + 1);

    31.       }

    32.       @Test

    33.       @DisplayName("描述测试用例")

    34.       void testWithDisplayName() {

    35.       System.out.println("testWithDisplayName");

    36.       }

    37.       @Test

    38.       @Disabled("这条用例暂时跑不过,忽略!")

    39.       void myFailTest(){

    40.       System.out.println("Disabled Testcase");

    41.       Assertions.assertEquals(1,2);

    42.       }

    43.       @Test

    44.       @DisplayName("运行一组断言")

    45.       public void assertAllCase() {

    46.       System.out.println("运行一组断言");

    47.           assertAll("groupAssert",

    48.                   () -> Assertions.assertEquals(2, 1 + 1),

    49.                   () -> Assertions.assertTrue(1 > 0)

    50.           );

    51.       }

    52.       @Test

    53.       @DisplayName("依赖注入1")

    54.       public void testInfo(final TestInfo testInfo) {

    55.           System.out.println(testInfo.getDisplayName());

    56.       }

    57.       @Test

    58.       @DisplayName("依赖注入2")

    59.       public void testReporter(final TestReporter testReporter) {

    60.           testReporter.publishEntry("name", "Alex");

    61.       }

    62.   }
    复制代码
    运行结果(缩进为了看起来方便,我自己设置的)
    1.  BeforeAll

    2.        BeforeEach

    3.           依赖注入1

    4.       AfterEach

    5.       BeforeEach

    6.           TestIdentifier [依赖注入2]

    7.            ReportEntry [timestamp = 2020-08-21T11:38:49.361976500, name = 'Alex’]

    8.        AfterEach

    9.       BeforeEach

    10.           myFirstTest

    11.       AfterEach

    12.       BeforeEach

    13.            testWithDisplayName

    14.       AfterEach

    15.       BeforeEach

    16.          运行一组断言

    17.       AfterEach

    18.   AfterAll
    复制代码
     注意:@BeforeAll、 @AfterALL注解方法必须是静态方法,否则会抛出运行时错误。  4. JUnit5 新加断言

    5. 异常断言  被测的程序
    1. public void divide(int n){

    2.       try {

    3.       result = result / n;

    4.       }catch(ArithmeticException ex){

    5.       System.out.println(ex);

    6.       throw new ArithmeticException("The n not allowed to 0!!");

    7.       }

    8.       }
    复制代码
    测试程序
    1.  @Test

    2.       @DisplayName("测试除0异常")

    3.       public void testDivideByZero() {

    4.           calculator.add(9);

    5.           Throwable exception = Assertions.assertThrows(ArithmeticException.class, () -> calculator.divide(0));

    6.           Assertions.assertEquals("The n not allowed to 0!!",exception.getMessage());

    7.   }
    复制代码
    6. 超时断言
    1. @Test
    2.       public void squareRoot()  {

    3.          Assertions.assertTimeoutPreemptively(Duration.of(2, ChronoUnit.SECONDS), () -> calculator.squareRoot(4))

    4.   }
    复制代码


    判断程序是否应该在两秒钟执行完毕。类似于JUnit4中的(timeout=XXX)。  7. 参数化测试
      7.1单参数
    1.  @ParameterizedTest

    2.   @ValueSource(ints = {1,2,3,4})

    3.   @DisplayName("参数化测试_单参数")

    4.   public void parameterizedTest(int param) {

    5.       calculator.add(param);

    6.       calculator.add(-1 * param);

    7.       Assertions.assertEquals(0, calculator.getResult());

    8.   }
    复制代码
    标签:  ·@ValueSource: 为参数化测试指定入参来源,支持八大基础类以及String类型,Class类型
      ·@NullSource: 表示为参数化测试提供一个null的入参
      ·@EnumSource: 表示为参数化测试提供一个枚举入参
      ValueSource类型:
      ·String values: @ValueSource(strings = {"foo", "bar", "baz"})
      ·Double values: @ValueSource(doubles = {1.5D, 2.2D, 3.0D})
      ·Long values: @ValueSource(longs = {2L, 4L, 8L})
      ·Integer values: @ValueSource(ints = {2, 4, 8})
      7.2 Enum参数
    1. import java.util.concurrent.TimeUnit;

    2.   …

    3.   @ParameterizedTest

    4.   @EnumSource(value = TimeUnit.class, names = {"SECONDS", "MINUTES"})

    5.   @DisplayName("参数化测试_Enum参数")

    6.   void testTimeUnitJustSecondsAndMinutes(TimeUnit unit) {

    7.   Assertions.assertTrue(EnumSet.of(TimeUnit.SECONDS, TimeUnit.MINUTES).contains(unit));

    8.   Assertions.assertFalse(EnumSet

    9.             .of(TimeUnit.DAYS, TimeUnit.HOURS, TimeUnit.MILLISECONDS, TimeUnit.NANOSECONDS,

    10.                   TimeUnit.MICROSECONDS).contains(unit));

    11.   }
    复制代码
    7.3参数化测试——方法参数(多参数)  注意:这个方法返回必须是个流
    1.    @ParameterizedTest

    2.       @MethodSource("paramGenerator")

    3.       @DisplayName("参数化测试_ 方法参数(多参数)")

    4.       void MethodParameForSquareRoot(int param, int result){  

    5.           calculator.squareRoot(param);

    6.           Assertions.assertEquals(result, calculator.getResult());

    7.       }

    8.   

    9.       static Stream<Arguments> paramGenerator(){

    10.           return Stream.of(Arguments.of(4,2), Arguments.of(9,3), Arguments.of(16,4));

    11.       }
    复制代码
    7.4.参数化测试——CVS文件参数化

    1. @ParameterizedTest

    2.       @CsvFileSource(resources = "data.csv")  //指定csv文件位置

    3.       @DisplayName("参数化测试-csv文件")

    4.       public void parameterizedCVSFile(int param, int result) {

    5.           calculator.squareRoot(param);

    6.           Assertions.assertEquals(result, calculator.getResult());

    7.       }
    复制代码
    其中,data.csv为:
    1. 42

    2. 93

    3. 164
    复制代码
    8.内嵌测试类  一般一个产品类对应一个测试类,但是使用JUnit,可以实现类的嵌套。
    1. package com.jerry;

    2.   import org.junit.jupiter.api.BeforeEach;

    3.   import org.junit.jupiter.api.DisplayName;

    4.   import org.junit.jupiter.api.Nested;

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

    6.   public class NestedTestDemo {

    7.       @Test

    8.       @DisplayName("Nested")

    9.       void isInstantiatedWithNew() {

    10.           System.out.println("最一层--内嵌单元测试");

    11.       }

    12.       @Nested

    13.       @DisplayName("Nested2")

    14.       class Nested2 {

    15.           @BeforeEach

    16.           void Nested2_init() {

    17.               System.out.println("Nested2_init");

    18.           }

    19.           @Test

    20.           void Nested2_test() {

    21.               System.out.println("第二层-内嵌单元测试");

    22.           }

    23.           @Nested

    24.           @DisplayName("Nested3")

    25.           class Nested3 {

    26.               @BeforeEach

    27.               void Nested3_init() {

    28.                   System.out.println("Nested3_init");

    29.               }

    30.               @Test

    31.               void Nested3_test() {

    32.                   System.out.println("第三层-内嵌单元测试");

    33.               }

    34.           }

    35.       }

    36.   }
    复制代码
    结果输出:  第一层--内嵌单元测试
      Nested2_init
      第二层-内嵌单元测试
      Nested2_init
      Nested3_init
      第三层-内嵌单元测试

    9. 重复测试
    1.  @RepeatedTest(5) //表示重复执行5次

    2.   @DisplayName("重复减法")

    3.   public void testSubstractManyTimes() {

    4.       calculator.add(5);

    5.       calculator.substract(3);

    6.       Assertions.assertEquals(2, calculator.getResult());

    7.   }
    复制代码
    这个测试用例将被执行5次,为什么设计这个方法,我个人没有理解。  10. 动态测试
    1. <strong> </strong>@TestFactory

    2.   @DisplayName("动态测试")

    3.   Iterator<DynamicTest> dynamicTests() {

    4.       return Arrays.asList(

    5.           dynamicTest("第1个动态测试", () ->{calculator.squareRoot(4);Assertions.assertEquals(2, calculator.getResult());}),

    6.           dynamicTest("第2个动态测试", () ->{calculator.squareRoot(9);Assertions.assertEquals(3, calculator.getResult());}),

    7.           dynamicTest("第3个动态测试", () ->{calculator.squareRoot(16);Assertions.assertEquals(4, calculator.getResult());}),

    8.           dynamicTest("第4个动态测试", () ->{calculator.squareRoot(25);Assertions.assertEquals(5, calculator.getResult());})

    9.       ).iterator();

    10.    }
    复制代码
    动态测试用得比较少,这个功能的原因我个人也不太理解。  11. 分组断言assertAll
    1.  @Test

    2.   @DisplayName("开根号分组断言")

    3.   public void testGroup() {

    4.       int[] parem = {4, 9, 16, 25, 36};

    5.       int[] result ={2, 3, 4, 5, 6};

    6.       Assertions.assertAll("parem,result",

    7.           () -> {calculator.squareRoot(parem[0]);Assertions.assertEquals(result[0], calculator.getResult());},

    8.           () -> {calculator.squareRoot(parem[1]);Assertions.assertEquals(result[1], calculator.getResult());},

    9.           () -> {calculator.squareRoot(parem[2]);Assertions.assertEquals(result[2], calculator.getResult());},

    10.           () -> {calculator.squareRoot(parem[3]);Assertions.assertEquals(result[3], calculator.getResult());},

    11.           () -> {calculator.squareRoot(parem[4]);Assertions.assertEquals(result[4], calculator.getResult());}

    12.      );
    复制代码
    分组断言中任一个断言的失败,都会将以 MultipleFailuresError 错误进行抛出提示。另外可以看出,使用分组断言也可以实现参数化



















    本帖子中包含更多资源

    您需要 登录 才可以下载或查看,没有帐号?(注-册)加入51Testing

    x
    分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
    收藏收藏
    回复

    使用道具 举报

    本版积分规则

    关闭

    站长推荐上一条 /1 下一条

    小黑屋|手机版|Archiver|51Testing软件测试网 ( 沪ICP备05003035号 关于我们

    GMT+8, 2024-11-24 06:29 , Processed in 0.067982 second(s), 25 queries .

    Powered by Discuz! X3.2

    © 2001-2024 Comsenz Inc.

    快速回复 返回顶部 返回列表