Jmockit示例三部曲之二让我验证下你是否走对了

上一章节我们主要讲的是在运行test case之前,在recorded阶段进行“期望”(可能会有些看不懂这个“期望”,实际上就是指对被mock的方法进行录制,希望被引用的方法返回自己设置的值,或者字段设置为自己设置的值)。这些“期望”是否真的在test case运行时发生了?一种是隐性的验证(如果是严格的类型,即在Expectations block中,或者是进行了引用次数times的限制,如果这些“期望”没有执行或者被引用的话,那么就会报AssertionError),另一种就是没有根本没有进行验证(如果是非严格类型,并且没有进行引用次数times的限制),当然第二种方式是不提倡的。

接下来我们将介绍使用Jmockit提供的第二种类型的mock API——Jmockit Verifications API,它允许我们使用显示的方式来验证在test case运行的时候,我们所期望的mock是否真的被引用了。

被测类依旧是序言中的MyBussinessService类,先将官网上的代码贴上,然后一起理解

package jmockit.tutorial.domain;

import java.util.*;
import static java.util.Arrays.*;
import org.apache.commons.mail.*;
import jmockit.tutorial.persistence.*;

import org.junit.*;
import mockit.*;

public final class MyBusinessService_VerificationsAPI_Test
{
   @Tested MyBusinessService service; // instantiated automatically
   @Mocked(stubOutClassInitialization = true) Database onlyStatics;
   @Capturing Email email; // concrete subclass mocked on demand, when loaded

   final EntityX data = new EntityX(5, "abc", "someone@somewhere.com");

   @Test
   public void doBusinessOperationXyzPersistsData() throws Exception
   {
      // No expectations recorded in this case.

      service.doBusinessOperationXyz(data);

(2)   new Verifications() {{ Database.persist(data); }};
   }

   @Test
   public void doBusinessOperationXyzFindsItemsAndSendsNotificationEmail() throws Exception
   {
      // Invocations that produce a result are recorded, but only those we care about.
      new NonStrictExpectations() {{
(1)      Database.find(withSubstring("select"), (Object[]) null);
         result = asList(new EntityX(1, "AX5", "someone@somewhere.com"));
      }};

      service.doBusinessOperationXyz(data);

      new VerificationsInOrder() {{
(3)      email.addTo(data.getCustomerEmail());
(4)      email.send();
      }};
   }
}
概括的说来,non-strict expectations相比较于strict expectations的不同之处在于:在test case的代码中,他可以被执行过,也可以不被执行,即使他们没有事先进行record,并且如果不是特别要求,他们被引用的顺序也是无关紧要的。

通过上面的例子指出,有两种方式可以使我们进行的“期望”是non-strict expectations类型的:第一种,就是干脆不要任何expectation block,就像第一个测试方法一样(doBussinessOperationXyzPersistsData());第二种就是在一个NonStrictExpectations block中进行指定“期望”,第二个测试方法就是一个例子。在第一个测试例子中,产品代码中被mock类型的所有调用都能被不限制的引用,但是non-void的方法根据自身的返回类型会默认返回一个合适的值(这个在后面的章节会提到),很显然,这是不合适的,所以在一个expecation block里面进行一些“期望”是有必要的。混合着使用严格型(strict-expectations)和非严格型(non-strict expectations)也是可以的,通过在被mock的类型前添加@NonStrict,或者在Expectations block中进行“期望”的时候使用notStrict方法。

当我们使用了non-strict expectations,在回放阶段调用的被mock的方法或者构造函数是否真的走了我们的“期望”而不是代码的真实逻辑,是不会立即进行验证的(除非显示的使用了times等调用次数限制)。这些非严格型的调用,在录制的时候被指定了一个特定的返回值,甚至是一个异常,在test case进行回放的时候都会产生作用。

事实是在non-strict expectations中进行显示的录制后允许测试方法通过了,就足以证明被测方法做的是正确的(因为在非严格型里面进行显示录制,必定是录制了返回值,甚至是指定了调用的次数,这就包括了验证了),在第二个测试例子中,如果将result=asList(…………)给注释掉,那么这个test case很有可能会fail掉,因为当其他的函数或者类型需要用到这个result的时候(只是默认的值,可能不能满足要求),或者是调用的验证失败了。在这个例子中,如果真的去掉了result=asList(…………),那么一个额外email.setMsg(withNotEqual(""))验证就需要添加到另外2个已有的验证中间。然而,在很多情况下,你需要确定被录制的引用至少被运行了1次,那么我们可以通过在录制的时候,使用minTimes=1来做到这一点。
non-strict expectations的另一个优势是他们可以显示的验证测试方法是否正确。这些verifications和录制有点像,但是是在Verification block中(或者像例子中的VerificationsInOrder,这个是Verification的子类,inorder表明是按照顺序进行验证的,顺序错了,test case就会fail掉,这个会在以后的章节进行介绍),这些验证是在测试方法执行之后进行验证的,也就是在回放阶段结束之后。而有times(或者maxTimes,minTimes)的,是在回放阶段就会进行验证。

从语法上来说,一个verification block是很像一个expectation block的。次数的限制对于测试方法的验证是很有用的,也是必须用的(要不然光mock了,测试通过了,进行录制的方法到底有没有运行都不知道),前面就提到过使用times,minTimes,以及maxTimes这三个字段,例如,如果一个被mock类中的方法在测试方法中从来没有被调用过,那么使用times=0(或者如果愿意使用maxTimes=0)来进行验证是十分正确的。

例子中的代码声明的类型,使用了新的方式(这里只是简单的介绍一下,详细的会在以后进行补充,如果急切需要了解,可以参考官方的API):

 @Tested MyBusinessService service; // instantiated automatically
 @Mocked(stubOutClassInitialization = true) Database onlyStatics;
 @Capturing Email email; // concrete subclass mocked on demand, when loaded
@Tested是可以帮我们自动生成被测的实例,而@Capturing是能在使用的时候,自动加载子类,可以和上一章的例子进行比较,上一章使用的是:
 @NonStrict SimpleEmail email; // calls to setters are unimportant, so we make it non-strict
使用@Capturing可以mock接口以及其所有的实现类,可以通过其属性classNames来指定特定的实现类进行mock,而不是其所有的实现类,在这一点上,可以和@Mocked进行比较,当我们使用@Mocked mock一个类时,其所有的父类(当然除了java.lang.Object)也都被mock了。

Verfications API就简单的介绍到这,预告Jmockit示例三部曲的第三部——按我自己的思路走。





  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值