Springboot Unit Test(单元测试)

这篇具有很好参考价值的文章主要介绍了Springboot Unit Test(单元测试)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

基本原则

单元测试,是指对程序中的最小可测试单元进行验证,在Java中的话,就是类。其有两个目的:

  • 验证程序实现的逻辑是否与设计的逻辑正确
  • 在涉及到代码修改时,用单元测试去保证原有功能不被破坏,

而一个好的单元测试应该具备以下FIRST 原则和AIR原则中的任何一条:

  • 单元测试的FIRST 规则
    • Fast 快速原则,测试的速度要比较快,
    • Independent 独立原则,每个测试用例应该互不影响,不依赖于外部资源。
    • Repeatable 可重复原则,同一个测试用例多次运行的结果应该是相同的
    • Self-validating 自我验证原则,单元测试可以自动验证,并不需要手工干预
    • Thorough 及时原则 单元测试必须即使进行编写,更新,维护。保证测试用例随着业务动态变化
  • AIR原则
    • Automatic 自动化原则 单元测试应该是自动运行,自动校验,自动给出结果。
    • Independent 独立原则 单元测试应该独立运行,吧相互之间无依赖,对外无依赖,多次运行之间无依赖。
    • Repeatable 可重复原则 单元测试是可重复运动的,每次的结果都稳定可靠。

一个整套完善的单元测试可以保障后续的增添功能时,程序迭代过程中,代码的逻辑正确性。验证程序的输入和输出与最初设计一致。这对后续的集成测试等会提供巨大的帮助。同时也会有利于集成测试的顺利进行。

单元测试粒度

目前一些代码扫描工具基本都给出了最低30%的单元测试代码覆盖率。这是一个最低限度,然而一个项目的覆盖率,要综合去考虑项目成本,人员安排等等因素。

关于单元测试的粒度,可以总结以下几点:

  • DAO层的单元测试: 对于基本CRUD,可以考虑跳过这一部分单元测试,而一些比较复杂的动态更新、查询等操作,建议用使用H2去做模拟单元测试。
  • Service层的单元测试:基本上一个Service里面肯定会依赖很多其他的service(此处也建议将成员变量通过构造方法进行注入,以便于单元测试去Mock),此时建议我们将依赖其他service的方法用Mock替代,Service里面的一些数据库的操作也进行Mock。这样可以保证service测试的独立性,不过对于逻辑复杂的方法可能要花很多时间在Mock上面。 如果发现需要Mock的方法过多,那么可能就需要考虑将要测试的方法是不是需要重构。
  • Controller(API)层的单元测试:主要着重测试HTTP status在 200,400,500 等情况下的异常处理,request及response的转换等。由于其余部分的代码测试都已经在其对应的单元测试覆盖,那么此时可以Mock绝大部分Serivce层中的方法。
  • 一般工具类的单元测试:一些工具类里面包含了比较多的逻辑,所以需要尽可能考虑多种情况下测试用例。

单元测试示例

单元测试可使用的第三方工具非常多,然而我们不可能精通每一个,只有在不断 的使用提高熟练程度。 对于SpringBoot而言可以直接引入spring-boot-starter-test , 它将会引入JUnit、Spring Test、AssertJ、Hamcrest(匹配对象) Mockito、JSONassert、JsonPath等工具库。

  1. 如下是一个关于用户登录功能的测试示例
 
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class UserBizImplTest extends ParentTest {
    @Resource
    UserBiz userBiz;

    @MockBean
    UserService userService;

    private static List<User> userList = new ArrayList<>();

    @BeforeClass
    public static void setUp() throws Exception {
        System.out.println("setUp");
        // mock userService

        int code = 102;
        for (int i = 0; i < 10; i++) {
            User user = new User();
            user.setId((long) i + 1);
            user.setUsername("Tom" + code);
            user.setPassword("P@ssw0rd");
            userList.add(user);
            code++;
        }
    }


    @AfterClass
    public static void tearDown() throws Exception {
        System.out.println("tearDown");
    }

@Test
    public void test_08_login() {
        // scenario 1: login success
        // input data
        LoginInfoDTO loginInfoDTO = new LoginInfoDTO();
        loginInfoDTO.setPassword("P@ssw0rd");
        loginInfoDTO.setUsername("admin");

        // mock data & methods
        String dbPassword = CommonUtils.encode(loginInfoDTO.getPassword());
        User user = new User();
        user.setUsername("admin");
        user.setPassword(dbPassword);

        Mockito.when(userService.getOne(Mockito.any())).thenReturn(user);

        // verify
        try {
            String token = userBiz.login(loginInfoDTO);
            System.out.println(token);
        } catch (Exception e) {
            TestCase.fail();
        }

        // scenario 2: user not exist
        // input data
        loginInfoDTO.setUsername("notExistedUser");

        //mock data & methods
        Mockito.when(userService.getOne(Mockito.any())).thenReturn(null);

        // verify
        try {
            String token = userBiz.login(loginInfoDTO);
            System.out.println(token);
            TestCase.fail();
        } catch (UserAuthorityException ignored) {
            System.out.println(ignored);
        } catch (Exception e) {
            TestCase.fail();
        }

        // scenario 3: password error
        // input data
        loginInfoDTO.setUsername("admin");
        loginInfoDTO.setPassword("wrongPassword");

        //mock data & methods
        Mockito.when(userService.getOne(Mockito.any())).thenReturn(user);

        // verify
        try {
            String token = userBiz.login(loginInfoDTO);
            System.out.println(token);
            TestCase.fail();
        } catch (UserAuthorityException ignored) {
            System.out.println(ignored);
        } catch (Exception e) {
            TestCase.fail();
        }
    }
}
  1. 代码详解:

这段代码是一个单元测试类,用于测试`UserBizImpl`类的登录功能。让我们逐步解释这段代码:

1. `@FixMethodOrder(MethodSorters.NAME_ASCENDING)`: 这是JUnit的一个注解,用于指定测试方法的执行顺序。在这里,它指定了按照方法名的字母顺序(升序)执行测试方法。

2. `public class UserBizImplTest extends ParentTest`: 这是测试类的定义,它继承了一个名为`ParentTest`的父类。

3. `@Resource UserBiz userBiz`: 使用`@Resource`注解注入了`UserBiz`类的一个实例,即要被测试的业务类。

4. `@MockBean UserService userService`: 使用`@MockBean`注解模拟了`UserService`类的实例,这个类是`UserBizImpl`的一个依赖。

5. `private static List<User> userList = new ArrayList<>();`: 定义了一个静态的`User`对象列表,用于存储模拟数据。

6. `@BeforeClass public static void setUp() throws Exception`: 在所有测试方法运行之前执行的方法。在这里,它用于准备测试数据,模拟`UserService`的行为。

7. `@AfterClass public static void tearDown() throws Exception`: 在所有测试方法运行之后执行的方法。在这里,它用于清理测试数据或资源。

8. `@Test public void test_08_login()`: 这是一个测试方法,用于测试用户登录功能。

9. 在`test_08_login`方法中:

   - 首先,定义了三个测试场景:

     - 登录成功的情况

     - 用户不存在的情况

     - 密码错误的情况

   - 对于每个场景,设置了输入数据(用户名和密码)和模拟的行为(使用`Mockito.when`方法模拟了`UserService`的`getOne`方法的返回值)。

   - 使用`userBiz`对象调用登录方法,并对返回结果进行验证。在成功登录和用户不存在的情况下,验证登录成功;在密码错误的情况下,验证抛出了`UserAuthorityException`异常。

这段代码通过模拟`UserService`的行为,测试了`UserBizImpl`类的登录功能在不同场景下的行为。

参考

SpringBoot单元测试指南 - 知乎文章来源地址https://www.toymoban.com/news/detail-842261.html

到了这里,关于Springboot Unit Test(单元测试)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • SpringBoot 如何使用 Spring Test 进行集成测试

    在开发过程中,单元测试是不可或缺的,它可以帮助我们及时发现代码的问题并进行修复,从而提高代码的质量和可维护性。但是,单元测试只能测试单个方法或类的功能,无法测试多个模块之间的交互和整个应用程序的功能。因此,为了确保应用程序的正确性和健壮性,我

    2024年02月10日
    浏览(34)
  • 【SpringBoot】SpringBoot单元测试

    单元测试(unit testing),是指对软件中的 最小可测试单元(方法) 进⾏检查和验证的过程就叫单元测试。 单元测试是开发者编写的⼀⼩段代码, ⽤于检验被测代码的⼀个很小的、很明确的(代码)功能是否正确 。执⾏单元测试就是 为了证明某段代码的执⾏结果是否符合我

    2023年04月17日
    浏览(29)
  • 单元测试|unittest生成测试报告

    测试报告为测试结果的统计即展示,是自动化测试不可或缺的一部分,利用unittest 可以生成测试报告。 使用第三方 HTMLTestRunner 执行测试用例集,生成网页版测试报告 HTMLTestRunner是Python标准库的unittest模块的一个扩展,在使用该模块之前 要下载HTMLTestRunner.py文件,并将该文件保

    2024年02月09日
    浏览(30)
  • Unittest单元测试之unittest用例执行顺序

    当在一个测试类或多个测试模块下,用例数量较多时,unittest在执行用例 (test_xxx)时,并不是按从上到下的顺序执行,有特定的顺序。 unittest框架默认根据ACSII码的顺序加载测试用例,数字与字母的顺序为: 0~9,A~Z,a~z。 对于类来说,class TestAxx 会优先于class TestBxx被执行。

    2024年02月13日
    浏览(28)
  • 单元测试、集成测试、功能测试——Unittest

     颗粒度最小,一般由开发小组采用白盒方式来测试,主要测试单元是否符合“设计”;是指 对软件中的最小可测试单元进行检查和验证  介于单元测试和系统测试之间,一般由开发小组采用白盒+黑盒的方法来测试,即验 证“设计”又验证“需求”。主要用来测试模板与模

    2023年04月08日
    浏览(30)
  • 单元测试(unit testing)到底是什么?

    做开发的同学应该都听说过单元测试(unit testing),因为对单元测试的理解程度不同,所以对单元测试的看法也可能有所不同。本文就来深入讲解一下单元测试的概念、作用和是否需要做单元测试。 单元测试(unit testing)是软件开发中的一种最低级别的测试方式,对软件中的

    2024年02月08日
    浏览(42)
  • [Python]unittest-单元测试

    目录 unittest的大致构成: Test Fixture Test Case-测试用例 Test Suite-测试套件 Test Runner 批量执行脚本 makeSuite() TestLoader discover() 用例的执行顺序 忽略用例执行 skip skipIf skipUnless 断言 HTML测试报告 错误截图 unittest是python中的单元测试框架 大致作用: 提供用例的组织与执行-组织大量的测

    2024年02月08日
    浏览(26)
  • unittest单元测试

    当你在编写测试用例时,可以使用Python内置的 unittest 模块来进行单元测试。下面是一个逐步指南,帮助你理解如何编写和运行基本的单元测试。 导入必要的模块 : 首先,你需要导入 unittest 模块和需要测试的模块(例如,你的 app.py )以及可能需要的其他模块。 import unitte

    2024年02月13日
    浏览(27)
  • 单元测试框架:unittest入门

    1、TestCase(测试用例): 一个testcase的实例就是一个测试用例 ;unittest 中执行测试的最小单元,通过验证 unittest 提供的 assert 方法来验证一组特定的操作和输入以后得到的响应;unittest 提供了一个名为 TestCase 的基础类,可以用来创建测试用例; 2、TestSuite(测试套件): 多

    2024年02月09日
    浏览(27)
  • UnitTesting 单元测试

      1.1 Unit Test : 单元测试   - test the business logic in your app : 测试应用中的业务逻辑   1.2 UI  Test :  界面测试   - test the UI of your app : 测试应用中的界面   1.3 测试书籍网址: 《Testing Swift》 https://www.hackingwithswift.com/store/testing-swift   2.1 创建 ViewModel,UnitTestingBootcampViewModel.swift  

    2024年02月07日
    浏览(27)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包