【问题标题】:Java Mockit : How to Mock a generic class method in JMockitJava Mockit:如何在 JMockit 中模拟泛型类方法
【发布时间】:2016-07-11 20:26:37
【问题描述】:

您好,我有以下课程

public class DataAccessLayer<T> {
  public T getData(Class<?> dataInfoType ,Integer id){
  //Some logic here
  } 
}

public class ServiceLayer{
    //this method has to be tested
     public Integer testingMethode{
         //The following line should be mocked
         UtilClass info =  new DataAccessLayer<UtilClass>().getData(UtilClass.class, 1); 
        retutn info.getSomeFieldWithIntegerValue();
     }
 }

我想为 testingMethode 编写测试用例,因为我需要在 DataAccessLayer&lt;T&gt; 中模拟 getData() 方法

jmockit 是否可以模拟 Template(Generic) 类?

【问题讨论】:

  • 在 mockito 中模拟泛型类的典型方法是定义一个非泛型子类(例如 class UtilClassDataAccessLayer extends DataAccessLayer&lt;UtilClass&gt;),然后创建该类的模拟。你能在 jmockit 中做类似的事情吗?
  • 我刚试过但不适合我。你能发布一个示例 sn-p 吗?

标签: java unit-testing generics junit jmockit


【解决方案1】:

可以像非泛型类一样模拟泛型类:

@Test
public void example(@Mocked final DataAccessLayer<UtilClass> mock)
{
    final UtilClass data = new UtilClass(123);
    new Expectations() {{ mock.getData(UtilClass.class, 1); result = data; }};

    int result = new ServiceLayer().testingMethode();

    assertEquals(123, result);
}

【讨论】:

  • 谢谢!这正是我想要的。
【解决方案2】:

在JMockit 中实际上不需要在ServiceLayer 类中创建一个保持变量,也不需要为DataLayer 创建一个参数化子类。以下测试工作正常:

package com.example.dsohl;

import static org.hamcrest.Matchers.equalTo;
import static org.junit.Assert.assertThat;

import org.junit.Test;
import org.junit.runner.RunWith;

import mockit.Deencapsulation;
import mockit.Expectations;
import mockit.Mocked;
import mockit.Tested;
import mockit.integration.junit4.JMockit;

@RunWith(JMockit.class)
public class TestTest {

    public static class UtilClass {
        public Integer foo() {
            return 5;
        }
    }

    public static class DataLayer<T> {
        public T getItem(Class<T> clazz, int itemId) {
            return null;
        }
    }

    public static class ServiceLayer {
        public Integer testMethod() {
            UtilClass util = new DataLayer<UtilClass>().getItem(UtilClass.class, 1);
            return util.foo();
        }
    }

// Test really begins here
    @Tested ServiceLayer svc;
    @Mocked DataLayer<UtilClass> data;
    @Mocked UtilClass util;

    @Test
    public void testDateSubtraction() throws Exception {
        new Expectations() {
            {
                new DataLayer<UtilClass>(); result = data;
                onInstance(data).getItem(UtilClass.class, 1); result = util;
                util.foo(); result = 37;
            }
        };

        Integer i = svc.testMethod();
        assertThat(i, equalTo(37));
    }

}

一些注意事项:首先,我的DataLayer.getItem() 返回null,所以如果注入失败,我们会得到NullPointerException,这很好而且很明显。显然你的代码不会像这样工作;这只是为了说服你。

其次,我使用onInstance(),这样我们就可以100% 确定DataLayer 构造函数的结果就是我们在接下来的测试步骤中使用的结果。 Expectations@Mocked 对象上的默认行为是记录对该类的任何对象的期望;这就是我们确定正在使用的是 我们的 对象的方式。 (通常我不担心这个,但在使用new 时我喜欢确定。)

最后,我省略了在这种情况下我可能会做的一些其他事情,比如使用Verifications 块等。只是尽量简单明了。

享受吧!

【讨论】:

    【解决方案3】:

    (我只能真正回答 Mockito,因为这是我最熟悉的;但同样的原则应该适用于其他模拟框架。

    首先,您需要能够将DataAccessLayer&lt;UtilClass&gt; 注入ServiceLayer,例如

    class ServiceLayer {
      private final DataAccessLayer<UtilClass> dal;
    
      ServiceLayer(DataAccessLayer<UtilClass> dal) {
        this.dal = dal;
      }
    
      public Integer testingMethode() {
        UtilClass info = dal.getData(UtilClass.class, 1);
        return info.getSomeFieldWithIntegerValue();
      }
    }
    

    这会破坏使用new 创建的与DataAccessLayer&lt;UtilClass&gt; 的静态耦合。

    现在,您可以通过创建非泛型子类来创建 DataAccessLayer&lt;UtilClass&gt; 的模拟实例:

    class UtilClassDataAccessLayer extends DataAccessLayer<UtilClass> {}
    

    然后创建一个模拟实例:

    DataAccessLayer<UtilClass> mocked = mock(UtilClassDataAccessLayer.class);
    

    现在,您可以根据需要配置此模拟,并将其传递给ServiceLayer

    ServiceLayer serviceLayer = new ServiceLayer(mocked);
    

    【讨论】:

    • 非常感谢这个解决方案!这是一个很好的工作想法,但仍然有任何可能的方法可以在不向 ServiceLayer 添加额外变量字段的情况下模拟它吗?因为根据我们当前此应用程序的设计模式,在 ServiceLayer 对象的整个生命周期中保留此变量并没有得到很好的理解。如果没有其他方法我宁愿跳过编写这个测试用例
    猜你喜欢
    • 1970-01-01
    • 2020-02-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-12-12
    • 1970-01-01
    • 2017-05-24
    相关资源
    最近更新 更多