51Testing软件测试论坛

标题: JMockit 如何 mock 异常 [打印本页]

作者: 胖虎    时间: 2019-3-22 15:35
标题: JMockit 如何 mock 异常
后来发现用 JMockit 来 mock 异常根本没有之前文中描述的那么复杂,其实还是在那个 result 上,给它赋个异常实例就轻而易举的解决了,只需如此
  1. new Expectations(MyService.class, ExternalService.class) {
  2.      {
  3.          ExternalService.fetchData();
  4.          result =  new NetworkException("No IPAddress ");
  5.      }
  6. };
复制代码
做过几篇 JMockit 使用 Expectations 来 Mock 方法,私有方法,私有属性的的日志,今天工作上突然有个需求是要 Mock 异常。现在再也不能为了跑个单元测试而去拔下网线了,也不该人为的去制造其他混乱来测试。开始是想能不能用 Expectations 来 Mock 异常,尚未发现相关的属性可以设置,没有类似 result 那样的属性,比如想像中有个 exception/throwable 属性:
  1. new Expectations(MyService.class, ExternalService.class) {
  2.      {
  3.          ExternalService.fetchData();
  4.          throwable =  new NetworkException("No IPAddress ");
  5.      }
  6. };
复制代码

可是没有 throwable 个属性,至少我还不知道如何用 Expectations 来 Mock 异常,此路不通,所以只得另辟溪径。我们可以直接 new MockUp 来创建类,这比创建一个 MockClass 来得轻量级些。


下面是一个完整例子,由四个类构成,今次列出

1. 要抛出的异常类 NetworkException.java

  1. package
  2. cc.unmi;



  3. public
  4. class  NetworkException extends
  5. RuntimeException {

  6.     public
  7. NetworkException(String message) {

  8.         super(message);

  9.     }

  10. }
复制代码


2. 被测试类 MyService.java

  1. package
  2. cc.unmi;



  3. public
  4. class  MyService {

  5.     public
  6. static  String fetchData(String name) {

  7.         return
  8. ExternalService.fetchByHttp(name);

  9.     }

  10. }
复制代码

调用 ExternalService.fetchByHttp() 方法,我们的测试用例将要 Mock 住这个方法,并抛出 NetworkException 异常。


3. 外部类,待 Mock 的 ExternalService.java

  1. package
  2. cc.unmi;



  3. public
  4. class  ExternalService {

  5.     public
  6. static  String fetchByHttp(String name) {

  7.         String result = null;

  8.         try
  9. {

  10.             // do something

  11.         } catch
  12. (Exception ex) {

  13.             throw
  14. new  NetworkException(ex.getMessage());

  15.         }

  16.         return
  17. result;

  18.     }

  19. }
复制代码

这是个示例方法,就上面的代码正常执行时肯定不会抛出 NetworkException 异常。我们假定在 //do something 的代码可能会抛出 NetworkException 异常,但我们可以在 Mock 方法中立即呈现出这个异常来。


4. 测试类 MyService.java,并完成异常的 Mock

  1. package
  2. cc.unmi;



  3. import
  4. mockit.Mock;

  5. import
  6. mockit.MockUp;



  7. import
  8. org.junit.Rule;

  9. import
  10. org.junit.Test;

  11. import
  12. org.junit.rules.ExpectedException;



  13. public
  14. class  MyServiceTest {



  15.     @Rule

  16.     public
  17. ExpectedException expectedEx = ExpectedException.none();



  18.     @Test

  19.     public
  20. void  testFetchData() {

  21.         new
  22. MockUp<ExternalService>() {

  23.             @Mock

  24.             public
  25. String fetchByHttp(String name) {

  26.                 throw
  27. new  NetworkException("No IPAddress");

  28.             }

  29.         };



  30.         expectedEx.expect(NetworkException.class);

  31.         expectedEx.expectMessage("No IPAddress");



  32.         MyService.fetchData("Yanbin");

  33.     }

  34. }
复制代码

这里用 new MockUp<>(){@Mock...} 的方式来 Mock 方法,我们也可以用 @MockClass..@Mock 的方式来创建 Mock 类/方法,但要笨重些。目前我们项目中基本摒弃了用 @MockClass 创建外部 Mock 类的做法,因为一般 Mock 类一般是与某一个测试方法紧密联系着的。

也要注意到 fetchByHttp() 本是个静态方法,但此处不能写成 public String static fetchByHttp(), 但去掉 static 也不会影响到 Mock 的效果。


测试运行成功,能够断言到所期待的异常类型和消息。

下面为演示 Mock 异常的正确而有效性,故意把 expectedEx.epectMessage("No IPAddress") 改成 expectedEx.epectMessage("NoNo IPAddress"),这样 JUnit  更能爆出有助于理解的错误信息来







欢迎光临 51Testing软件测试论坛 (http://bbs.51testing.com/) Powered by Discuz! X3.2