JUnit + Mockito 单元测试

JUnit 是单元测试框架。Mockito 与 JUnit 不同,并不是单元测试框架(这方面 JUnit 已经足够好了),它是用于生成模拟对象或者直接点说,就是”假对象“的工具。一个典型的例子就是使用模拟对象来模拟数据库DAO层。在生产环境上是使用运行的数据库,但是在单元测试环境中完全可以用模拟对象来模拟数据,确保单元测试的正确条件。这样就不需要依赖于外部的数据。一般通常的做法就是联合 JUnit + Mockito 来进行测试。

入门

首先是配置 Mock 对象,

List mock = mock( List.class );
when( mock.get(0) ).thenReturn( 1 );
assertEquals( "预期返回1", 1, mock.get( 0 ) );

再例如,假设我们没有 Tomcat(虽然不太可能,假设吧!),使用 Mockito 模拟一个:

HttpServletRequest request = mock(HttpServletRequest.class);
when(request.getParameter("a")).thenReturn("aaa");

其中 request 是模拟 HttpServletRequest 的对象,拥有 HttpServletRequest 的所有方法和属性。when(xxxx).thenReturn(yyyy); 是指定当执行了这个方法的时候,返回 thenReturn 的值,相当于是对模拟对象的配置过程,为某些条件给定一个预期的返回值。相信通过这个简单的例子你可以明白所谓 Mock 便是这么一回事。

这里就是" Stub 打桩"的概念了,所谓打桩,就是把所需的测试数据,适用于基于状态的(state-based)测试,关注的是输入和输出。

对方法设定返回异常,需指定类型,参见 这里 。

when(i.next()).thenThrow(new RuntimeException());

Mockito支持 迭代风格 的返回值设定,

  • 第一种方式 when(i.next()).thenReturn("Hello").thenReturn("World");
  • 第二种方式 when(i.next()).thenReturn("Hello", "World");

上面的例子等价于:

when(i.next()).thenReturn("Hello");
when(i.next()).thenReturn("World");

第一次调用i.next()将返回”Hello”,第二次的调用会返回”World”。

对 void 方法不返回值,所以不能 when(mock.someMethod()).thenReturn(value) 这样的语法,可以这样

doNothing().when(i).remove();
doThrow(Throwable) 模拟返回异常
doThrow(new RuntimeException()).when(i).remove();

迭代风格 doNothing().doThrow(new RuntimeException()).when(i).remove();,这样,第一次调用remove方法什么都不做,第二次调用抛出RuntimeException异常。

模拟参数argument matchers

这个比较方便,anyInt() 匹配任何 int 参数,这意味着参数为任意值,其返回值均是 element  

when(mockedList.get(anyInt())).thenReturn("element");   
System.out.println(mockedList.get(999));// 此时打印是element

若方法中的某一个参数使用了matcher,则所有的参数都必须使用 matcher。

自定义类型也可以,参加 这里 。

模拟 Servlet

验证

实话说,我刚接触也不是太明白,参见 《用mockito的verify来验证mock的方法是否被调用》 :

看mockito的api时,一直都不清楚veriry()这个方法的作用,因为如果我mock了某个方法,肯定是为了调用的啊。直到今天在回归接口测试用例的时候,发现有两个用例,用例2比用例1多了一个 mock 的步骤,不过最后的结果输出是一样的。由于代码做了修改,我重新 mock 后,其实用例2中对于的步骤是不会执行的,可测试还是通过了。仔细查看后,发现mock的方法没有被调用,所以用例2和用例1就变成一样的了。于是,就产生了这么个需求:单单通过结果来判断正确与否还是不够的,我还要判断是否按我指定的路径执行的用例。到这里,终于领略到了mockito的verify的强大威力,以下是示例代码:

若调用成功,则程序正常运行,反之则会报告: Wanted but not invoked:verify(mockedList).add("one"); 错误。

using mocks
mockedList.add("one");
mockedList.add("two");
verify(mockedList).add("one"); // 注意,如果times不传入,则默认是1

据说是 Mockito 跟踪了所有的方法调用和参数的调用情况。verify() 可以验证方法的行为。查看另外一个的例子:

@Test
public void testMap() {
  Map mock = Mockito.mock( Map.class );
  Mockito.when( mock.get( "city" ) ).thenReturn( "深圳" );    
  // test code
  assertEquals( "城市测试", "深圳", mock.get( "city" ) );    
  Mockito.verify(mock).get( Matchers.eq( "city" ) );
  Mockito.verify( mock, Mockito.times( 2 ) );
}

更多验证的例子参见 这里 。

其他高级话题

如果没有 JUnit,可以使用 Mockito 的 @Before 的注解,进行一些前期的初始化工作,

public class ArticleManagerTest {
  @Mock private ArticleCalculator calculator;
  @Mock private ArticleDatabase database;
  @Mock private UserProvider userProvider;
  @Before public void setup() {
    MockitoAnnotations.initMocks(testClass);
  }
}

如果有 JUnit,则无需 @Before,但要修改 JUnit 默认容器,

@RunWith(MockitoJUnitRunner.class)
public class ExampleTest {
    @Mock private List list;

    @Test public void shouldDoSomething() {
        list.add(100);
    }
}

在 JUnit 中有很多个 Runner ,他们负责调用你的测试代码,每一个 Runner 都有各自的特殊功能,你要根据需要选择不同的 Runner 来运行你的测试代码。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 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、付费专栏及课程。

余额充值