单测的思路

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

单测的分类

  • 单元测试(Unit Testing)是一种软件开发中的测试方法,它的主要目的是确保软件中的最小可测试单元(通常是函数、方法或类)在被单独测试和验证时能够按照预期工作。尽管单元测试有很多优点,如提高代码质量、减少Bug、简化调试过程等,但它也存在一些缺点:
    • 增加开发时间:如要求覆盖率到80%甚至90%,或者入参几十个难以构造,单测时间占比可能超过30%。
    • 需要维护:随着代码的改变,特别是大规模的重构,单元测试也需要相应地更新和维护,增加开发的负担。
    • 无法发现对其他类的影响:单元测试主要关注单个单元的行为,无法发现与多个单元交互或整个系统相关的问题。
  • 按照接口、场景维度调用对应的方法。
    • 优点有:
      • 减少开发时间:mock框架搭起来后只需要构造入参、和个别新增的下游依赖。
      • 维护成本低:接口内部的重构不会影响到单测的入参和出参。
      • 可以发现对其他类的影响:一次调用涉及到多个类,可以测出对其他类甚至其他接口的影响。
    • 缺点有:
      • 分支逻辑覆盖困难。如果接口涉及10个串联的类,每个类有2个分支,则需要构造1024个入参,远超方法维度单测的20个。
  • 所以最好能同时使用两种单测,做到优势互补。
    • 方法的单测:覆盖入参少、业务分支多的场景。
    • 接口、场景的单测:覆盖主干接口。

方法的单测

推荐用更智能的squaretest生成单测模板后,手工调整。

生成工具的对比

  • squaretest
    • 优点:
      • 生成测试用例相对智能,自动生成入参、覆盖部分if分支。
    • 缺点:
      • 只有30天的免费试用期,之后需要付费使用。事实上点掉reminder后可以继续使用。
  • TestMe
    • 优点:
      • 简单易用,适合初学者或小型项目使用。
    • 缺点:
      • 生成的测试用例不够全面或深入, 需要手动填充输入参数、写分支逻辑。
  • EvoSuite
    • 优点:
      • 作为Maven插件使用,方便集成到Java项目中。
    • 缺点:
      • 社区支持相对较少,遇到问题时可能难以得到及时帮助。
      • 配置和使用可能相对复杂,需要一定的学习成本,如需要引入groovy等外部依赖
  • diffblue
    • 优点:
      • 与IntelliJ IDEA集成良好,使用方便。
      • 支持多种编程语言和框架。
    • 缺点:
      • 商用版本收费较高,对于个人用户或小型团队可能不太友好。
      • 生成单测较慢,一个类近1Min。

生成步骤

  1. 安装插件
    单测的思路,java,单元测试

  2. 引入依赖

    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-test</artifactId>
      <version>2.1.1.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.junit.jupiter</groupId>
      <artifactId>junit-jupiter</artifactId>
      <version>5.8.2</version>
    </dependency>
  1. 编写业务代码
@Service
public class TestServiceImpl implements TestService {

    @Resource
    private TestRepository testRepository;
    @Resource
    private TestThird testThird;

    @Override
    public void start(InputDTO inputDTO) {
        if (testRepository.select(inputDTO.getId())==null) {
            testRepository.insert(new InputEntity());
        }
        testThird.callThird(new InputEntity());
    }
}

  1. 生成单测
    单测的思路,java,单元测试单测的思路,java,单元测试
  2. 单测生成结果
class TestServiceImplTestSquaretest {

    @Mock
    private TestRepository mockTestRepository;
    @Mock
    private TestThird mockTestThird;

    @InjectMocks
    private TestServiceImpl testServiceImplUnderTest;

    @BeforeEach
    void setUp() {
        initMocks(this);
    }

    @Test
    void testStart() {
        // Setup
        final InputDTO inputDTO = new InputDTO();
        inputDTO.setName("name");
        inputDTO.setId(0);
        final InputDetail inputDetail = new InputDetail();
        inputDetail.setName("name");
        inputDTO.setInputDetail(inputDetail);

        // Configure TestRepository.select(...).
        final InputEntity inputEntity = new InputEntity();
        inputEntity.setId(0);
        inputEntity.setName("name");
        when(mockTestRepository.select(0)).thenReturn(inputEntity);

        // Run the test
        testServiceImplUnderTest.start(inputDTO);

        // Verify the results
        verify(mockTestThird).callThird(any(InputEntity.class));
    }

    @Test
    void testStart_TestRepositorySelectReturnsNull() {
        // Setup
        final InputDTO inputDTO = new InputDTO();
        inputDTO.setName("name");
        inputDTO.setId(0);
        final InputDetail inputDetail = new InputDetail();
        inputDetail.setName("name");
        inputDTO.setInputDetail(inputDetail);

        when(mockTestRepository.select(0)).thenReturn(null);

        // Run the test
        testServiceImplUnderTest.start(inputDTO);

        // Verify the results
        verify(mockTestRepository).insert(any(InputEntity.class));
        verify(mockTestThird).callThird(any(InputEntity.class));
    }
}

class TestServiceImplTestTestMe {

    @Mock
    TestRepository testRepository;
    @Mock
    TestThird testThird;
    @InjectMocks
    TestServiceImpl testServiceImpl;

    @BeforeEach
    void setUp() {
        MockitoAnnotations.initMocks(this);
    }

    @Test
    void testStart() {
        when(testRepository.select(anyInt())).thenReturn(new InputEntity());
        when(testRepository.insert(any())).thenReturn(Integer.valueOf(0));

        testServiceImpl.start(new InputDTO());
    }
}

接口的单测

mock步骤

mock外部依赖,启动容器,调用接口

  1. 编写外部依赖的mock类
@Service
public class TestThirdImpl implements TestThird {

    @Override
    public void callThird(InputEntity entity) {
        System.out.println("TestThirdImpl callThird");
    }
}
//mock
public class TestThirdMockImpl implements TestThird {

    public void callThird(InputEntity entity) {
        System.out.println("TestThirdMockImpl callThird");
    }
}

  1. 替换容器中的beanDefinition
@Configuration
public class MockConfig {

    @Bean
    public BeanDefinitionRegistryPostProcessor beanDefinitionRegistryPostProcessor() {
        return new BeanDefinitionRegistryPostProcessor() {
            @Override
            public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
                //移除依赖的bean
                registry.removeBeanDefinition("testThirdImpl");
                //获取Mockbean的定义
                BeanDefinition beanDe = BeanDefinitionBuilder.rootBeanDefinition(TestThirdMockImpl.class).getBeanDefinition();
                //注册mockbean
                registry.registerBeanDefinition("testThirdImpl", beanDe);
            }

            @Override
            public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {

            }
        };
    }
}
  1. test模块中启动容器,并调用入口方法
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = TestApplication.class)
public class TestApplicationTest {

    @Resource
    private TestService testService;

    @Test
    public void start() {
        testService.start(new InputDTO());
    }

}

部分依赖mock的方式

  1. 数据库。用h2数据库mock。
public class MockDataSource extends HikariDataSource {

    public MockDataSource() {
        this.setDriverClassName("org.h2.Driver");
        this.setJdbcUrl("jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;MODE=MySQL;");
        this.setRegisterMbeans(true);
        this.setPoolName("mock");
    }
}

场景的单测

将接口单测组合文章来源地址https://www.toymoban.com/news/detail-826507.html

@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = TestApplication.class)
public class TestApplicationTest {

    @Resource
    private TestService testService;

    @Test
    public void start() {
        testService.start(new InputDTO());
        testService.end(new InputDTO());
    }

}

参考

  • 告别加班/解放双手提高单测覆盖率之Java 自动生成单测代码神器推荐
  • 单元测试 - 单元测试集成方案
  • JUnit 5 User Guide
  • 关于testNG和JUnit的对比
  • JUnit 5 单元测试教程
  • Junit5文档
  • 单元测试自动生成工具EvoSuite的简单使用
  • 使用BeanDefinitionRegistryPostProcessor动态注入BeanDefinition
  • 使用h2数据库支持单元测试
  • 使用H2数据库来模拟进行单元测试
  • H2官网
  • 关于springboot项目(@SpringBootTest单元测试类)找不到配置文件问题
  • Run Both JUnit 4 and Junit5 With Maven Surefire Plugin
  • 解决 Spring Boot 启动时 TypeNotPresentExceptionProxy / ArrayStoreException 异常
  • Maven的单元测试没有执行的问题

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

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

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

相关文章

  • 单元自测Java 单元测试规范

    目录 1、前言 1.1 定义 1.2 单元测试CheckList 1.3 测试模型 1.3.1 冰淇淋模型 1.3.2 金字塔模型 1.4 为什么要做单元测试 1.5单元测试编码规则 1.6 单元测试用例的设计要素  2、测试框架介绍 3、单元测试开发规范 3.1 注意事项 3.2 命名规范 3.3 输入数据规范 3.4 结果校验规范         单

    2024年02月15日
    浏览(38)
  • java的单元测试-mock测试

    对于普通的方法,通常采用断言测试。 对于接口,需要使用mockMvc 对于未开发的功能,需要mockBean模拟一个业务bean java自身携带的工具类,也可以用于一些对抛出异常要求不高的业务或者存在全局异常的项目 另外有一个更加简单的写法,以assert开头 曾使用注入方式得到mockM

    2023年04月08日
    浏览(51)
  • 【Java】Java(四十七):单元测试

    JUnit是一个 Java 编程语言的单元测试工具。JUnit 是一个非常重要的测试工具 JUnit是一个开放源代码的测试工具。 提供注解来识别测试方法。 JUnit测试可以让你编写代码更快,并能提高质量。 JUnit优雅简洁。没那么复杂,花费时间较少。 JUnit在一个条中显示进度。如果运行良好

    2024年02月08日
    浏览(45)
  • 单元测试练习(JAVA版)

    题目来源于:https://blog.csdn.net/weixin_57099902/article/details/131430247 题目1: 分析题目: 得到答案: 题目2: 分析题目: 得到答案: 题目3: 分析题目: 得到答案: 题目4: 分析题目: 得到答案:

    2024年04月23日
    浏览(25)
  • java单元测试(调试)

    **黑盒测试:**不需要写代码,给输入值,看程序是否能够输出期望的值。 **白盒测试:**需要写代码的。关注程序具体的执行流程。 JUnit 是由 Erich Gamma 和 Kent Beck 编写的一个测试框架(regression testing framework),供Java开发人员编写单元测试之用。 JUnit测试是程序员测试,即所

    2024年02月16日
    浏览(39)
  • Java 单元测试

    什么是单元测试 单元测试(unit testing),是指对软件中的最小可测试单元进行检查和验证,简单来说就是测试部分代码,对代码中的问题快速定位,及时修复。 什么是JUnit JUnit就是一个Java语言的单元测试框架,用于编写和运行可重复的测试。 JUnit的优势 可以对代码进行单元

    2024年02月11日
    浏览(26)
  • Java单元测试

            ​在Java项目中,单元测试虽然不会编译且部署到服务器上,但是单测对于一个项目来说还是很重要的。好的单元测试可以充分发现代码里边的隐藏bug,简化调试,极大的降低上线的风险,为运维以及测试大大降低工作量,降低项目的成本。         最近项目频

    2024年02月11日
    浏览(24)
  • java 单元测试Junit

    所谓 单元测试 ,就是针对最小的功能单元,编写测试代码对其进行正确性测试。为了测试更加方便,有一些第三方的公司或者组织提供了很好用的测试框架,给开发者使用。这里介绍一种Junit测试框架。Junit是第三方公司开源出来的,用于对代码进行单元测试的工具(IDEA已经

    2024年02月07日
    浏览(65)
  • java-单元测试

    单元测试(unit testing),是指对软件中的最小可测试单元进行检查和验证。至于“单元”的大小或范围,并没有一个明确的标准,“单元”可以是一个函数、方法、类、功能模块或者子系统。 单元测试通常和白盒测试联系到一起 ,如果单从概念上来讲两者是有区别的,不过

    2024年02月07日
    浏览(30)
  • JAVA PowerMock 单元测试

    单元测试针对程序模块来进行正确性检验的测试工作 单元测试 集成测试 编写人员 开发 开发 编写场地 生产代码仓库内 生产代码仓库内 编写时间 代码发布前 代码发布前 覆盖面积 代码行覆盖60-80% 分支覆盖40-60% 功能级别覆盖 环境依赖 代码级别,不依赖环境 依赖日常或本地

    2024年02月03日
    浏览(33)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包