junit依赖_使用 Junit + Mockito 实践单元测试

一、前言

有同学可能看到这个标题,又以为是标题党了,你真莫笑,你可以小声去问问你在中小型公司的同学,有多少在写单测?可能有的同学就只知道Junit,连Mockito是什么都不知道,希望本文能帮助你深入的了解单测框架。

相信做过开发的同学,都多多少少写过下面的代码,很长一段时间我一直以为这就是单元测试...

@SpringBootTest
@RunWith(SpringRunner.class)
public class UnitTest1 {

    @Autowired
    private UnitService unitService;

    @Test
    public void test() {
        System.out.println("----------------------");
        System.out.println(unitService.sayHello());
        System.out.println("----------------------");
    }
}

但这是单元测试嘛?unitService 中可能还依赖了 Dao 的操作;如果是微服务,可能还要起注册中心。那么这个“单元”也太大了吧!如果把它称为集成测试,可能更恰当一点,那么有没有可能最小粒度进行单元测试嘛?

单元测试应该是一个带有隔离性的功能测试。在单元测试中,应尽量避免其他类或系统的副作用影响。

单元测试的目标是一小段代码,例如方法或类。方法或类的外部依赖关系应从单元测试中移除,而改为测试框架创建的 mock 对象来替换依赖对象。

单元测试一般由开发人员编写,通过验证或断言目标的一些行为或状态来达到测试的目的。

二、JUnit 框架

JUnit 是一个测试框架,它使用注解来标识测试方法。JUnit 是 Github 上托管的一个开源项目。

一个 JUnit 测试指的是一个包含在测试类中的方法,要定义某个方法为测试方法,请使用 @Test 注解标注该方法。该方法执行被测代码,可以使用 JUnit 或另一个 Assert 框架提供的 assert 方法来检查预期结果与实际结果是否一致,这些方法调用通常称为断言或断言语句。

public class UnitTest2 {

    @Test
    public void test() {
        String sayHello = "Hello World";
        Assert.assertEquals("Hello World", sayHello);
    }
}

以下是一些常用的 JUnit 注解:

注解描述
@Test将方法标识为测试方法
@Before在每次测试之前执行。用于准备测试环境(例如,读取输入数据,初始化类)
@After每次测试之后执行。用于清理测试环境(例如,删除临时数据,恢复默认值)
@BeforeClass用于 static方法,在所有测试开始之前执行一次。它用于执行耗时的活动,例如:连接到数据库
@AfterClass用于 static方法,在完成所有测试之后,执行一次。它用于执行清理活动,例如:与数据库断开连接
@Ignore指定要忽略的测试
@Test(expected = Exception.class)如果该方法未引发命名异常,则失败
@Test(timeout=100)如果该方法花费的时间超过100毫秒,则失败

以下是一些常用的 Assert 断言:

声明描述
fail([message])使方法失败。在执行测试代码之前,可用于检查未到达代码的特定部分或测试失败
assertTrue([message,]布尔条件)检查布尔条件是否为真
assertFalse([message,]布尔条件)检查布尔条件是否为假
assertEquals([message,]预期,实际)测试两个值是否相同。注意:对于数组,会检查引用而不是数组的内容
assertNull([message,]对象)检查对象是否为空
assertNotNull([message,]对象)检查对象是否不为空
assertSame([message,]预期,实际)检查两个变量是否引用同一对象
assertNotSame([message,]预期,实际)检查两个变量是否引用了不同的对象

三、Mockito 框架

从上面的介绍我们可以认识到,如何减少对外部的依赖才是实践单元测试的关键。而这正是 Mockito 的使命,Mockito 是一个流行的 mock 框架,可以与 JUnit 结合使用,Mockito 允许我们创建和配置 mock 对象,使用 Mockito 将大大简化了具有外部依赖项的类的测试开发。spring-boot-starter-test 中默认集成了 Mockito,不需要额外引入。

在测试中使用 Mockito,通常会:

  • mock 外部依赖关系并将 mock 对象插入待测代码

  • 执行被测代码

  • 验证代码是否正确执行43b139f4e683aaaf5f9bf284a2289986.png

3.1 使用 Mockito 创建 mock 对象

Mockit o提供了几种创建 mock 对象的方法:

  • 使用静态 mock() 方法

  • 使用 @Mock 注解

如果使用 @Mock 注解,则必须触发创建带有 @Mock 注解的对象。使用 MockitoRule 可以做到,它通过调用静态方法 MockitoAnnotations.initMocks(this) 来填充带 @Mock 注解的字段。或者可以使用 @RunWith(MockitoJUnitRunner.class)。

public class UnitTest3 {

    // 触发创建带有 @Mock 注解的对象
    @Rule public MockitoRule mockitoRule = MockitoJUnit.rule();
    // 1. 使用 @Mock 注解创建 mock 对象
    @Mock private UnitDao unitDao;

    @Test
    public void test() {
        // 2. 使用静态 mock() 方法创建 mock 对象
        Iterator iterator = mock(Iterator.class);
        // when...thenReturn / doReturn...when 模拟依赖调用
        when(iterator.next()).thenReturn("hello");
        doReturn(1).when(unitDao).delete(anyLong());
        // 断言
        Assert.assertEquals("hello", iterator.next());
        Assert.assertEquals(new Integer(1), unitDao.delete(1L));
    }
}

3.2 使用 mock 对象实践单元测试

我们要单元测试的内容,常常包含着对数据库的访问等等,那么我们要如何 mock 掉这部分调用呢?我们可以使用 @InjectMocks 注解创建实例并使用 mock 对象进行依赖注入。

@Service
public class UnitServiceImpl implements UnitService {

    @Autowired
    private UnitDao unitDao;

    @Override
    public String sayHello() {
        Integer delete = unitDao.delete(1L);
        System.out.println(delete);
        return "hello unit";
    }
}
@RunWith(MockitoJUnitRunner.class)
public class UnitTest2 {

    @Mock
    private UnitDao unitDao;
    @InjectMocks
    private UnitServiceImpl unitService;

    @Test
    public void unitTest() {
        // mock 调用
        when(unitDao.delete(anyLong())).thenReturn(1);
        Assert.assertEquals("hello unit", unitService.sayHello());
    }
}

Mockito 还有很多有趣的实践,比如:@Spy或spy()方法、verify()验证等等,鉴于篇幅原因,读者可自行挖掘。

3.3 使用 PowerMock mock 静态方法。

Mockito 也有一些局限性。例如:不能 mock 静态方法和私有方法。这个时候我们就要用到 PowerMock,PowerMock 支持 JUnit 和 TestNG,扩展了 EasyMock 和 Mockito 框架,增加了mock static、final 方法的功能。

首先需要引入 PowerMock 的依赖:

       
        <dependency>
            <groupId>org.powermockgroupId>
            <artifactId>powermock-module-junit4artifactId>
            <version>2.0.7version>
            <scope>testscope>
        dependency>
        <dependency>
            <groupId>org.powermockgroupId>
            <artifactId>powermock-api-mockito2artifactId>
            <version>2.0.7version>
        dependency>

接下来就能愉快的 mock 静态方法了。

@RunWith(PowerMockRunner.class)
@PrepareForTest({StringUtils.class})
public class UnitTest4 {

    @Test
    public void test() {
        mockStatic(StringUtils.class);
        when(StringUtils.getFilename(anyString())).thenReturn("localhost");
        Assert.assertEquals("localhost", StringUtils.getFilename(""));
    }
}
来源:cnblogs.com/jmcui/p/12802099.html

46c7d37a2f523f2c8da258786d478745.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring Boot是一个用于构建Java应用程序的开源框架,它提供了一种简化了配置的方式来快速构建应用程序。JUnit是一个用于编写和运行单元测试的开源测试框架,而Mockito是一个用于创建和管理模拟对象的Java库。 下面是一个使用Spring Boot、JUnitMockito进行单元测试的示例: 假设我们有一个UserService类,它依赖于一个UserRepository接口来访问数据库并进行一些操作。我们想要对UserService的方法进行单元测试。 首先,我们需要创建一个测试类,命名为UserServiceTest。在测试类中,我们将使用JUnit的注解来标记测试方法,并使用Mockito来创建模拟对象。示例代码如下: ```java @RunWith(MockitoJUnitRunner.class) public class UserServiceTest { @InjectMocks private UserService userService; @Mock private UserRepository userRepository; @Test public void testGetUserById() { // 配置模拟对象的行为 User user = new User("1", "John"); when(userRepository.findById("1")).thenReturn(user); // 调用被测试的方法 User result = userService.getUserById("1"); // 验证结果 assertEquals("John", result.getName()); } } ``` 在上面的示例中,我们使用了@RunWith注解来指定使用MockitoJUnitRunner运行测试,这样就能自动创建和管理模拟对象。使用@InjectMocks注解将被测试的对象自动注入到测试类中,使用@Mock注解创建模拟对象。 在testGetUserById方法中,我们首先使用when方法配置userRepository模拟对象的行为,表示当传入参数为"1"时,返回一个指定的User对象。 然后,我们通过调用userService的getUserById方法来测试该方法的逻辑。最后,使用assertEquals断言来验证结果是否符合预期。 以上就是一个使用Spring Boot、JUnitMockito进行单元测试的示例。通过使用Mockito创建模拟对象,我们可以更容易地测试各个方法的逻辑,而不依赖于实际的数据库。这样可以提高测试效率并确保代码的质量。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值