简体   繁体   English

Java Mockit:如何在JMockit中模拟通用类方法

[英]Java Mockit : How to Mock a generic class method in JMockit

Hi I have the following classes 嗨,我有以下课程

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();
     }
 }

I want to write test cases for testingMethode for that I need to mock the getData() method in DataAccessLayer<T> 我想为testingMethode编写测试用例,因为我需要在DataAccessLayer<T>模拟getData()方法

Is it possible with jmockit to mock a Template(Generic ) class? jmockit是否可以模拟Template(Generic)类?

In JMockit there's actually no need to create a holding variable in the ServiceLayer class, nor is there a need to make a parameterized subclass of your DataLayer . 在JMockit中,实际上不需要在ServiceLayer类中创建一个保持变量,也不需要为DataLayer创建参数化的子类。 The following test works just fine: 以下测试可以正常工作:

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));
    }

}

A few notes: First, my DataLayer.getItem() returns null so if the injection fails, we get a NullPointerException , nice and obvious. 一些注意事项:首先,我的DataLayer.getItem()返回null,因此,如果注入失败,我们将得到NullPointerException ,很明显。 Obviously your code won't work like this; 显然,您的代码无法像这样工作; this is only to convince you. 这只是说服您。

Second, I use onInstance() so that we can be 100% certain that the result of the DataLayer constructor is what we are using in the next steps of the test. 其次,我使用onInstance()以便可以100%确定DataLayer构造函数的结果是我们在测试的下一步中使用的结果。 The default behaviour of Expectations on a @Mocked object is to record the expectation against any object of that class; @Mocked对象上的Expectations的默认行为是针对该类的任何对象记录期望; this is how we are certain that it's our object that's being used. 这就是我们确定正在使用的是我们的对象的方式。 (Ordinarily I don't worry myself about this, but when using new I like to be certain.) (通常我不必为此担心,但是在使用new我想确定一下。)

Finally, I'm omitting some other stuff I might do in cases like this, like use a Verifications block, etc. Just trying to be as straightforward as possible. 最后,我省略了在这种情况下可能要做的其他事情,例如使用Verifications块等。只是尝试尽可能简单明了。

Enjoy! 请享用!

A generic class can be mocked the same way a non-generic one: 通用类可以像非通用类一样进行模拟:

@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);
}

(I can only really answer for Mockito, as that is what I am most familiar with; but the same principle should be applicable in other mocking frameworks). (我只能真正回答Mockito,因为这是我最熟悉的;但是相同的原理应该适用于其他模拟框架)。

Firstly, you need to be able to inject a DataAccessLayer<UtilClass> into ServiceLayer , eg 首先,您需要能够将DataAccessLayer<UtilClass>注入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();
  }
}

This breaks the static coupling to the DataAccessLayer<UtilClass> created by the use of the new . 这打破了与使用new创建的DataAccessLayer<UtilClass>的静态耦合。

Now, you can create a mocked instance of DataAccessLayer<UtilClass> by creating a non-generic subclass: 现在,您可以通过创建一个非通用子类来创建DataAccessLayer<UtilClass>DataAccessLayer<UtilClass>实例:

class UtilClassDataAccessLayer extends DataAccessLayer<UtilClass> {}

and then create a mock instance: 然后创建一个模拟实例:

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

Now, you can configure this mock as you need, and pass it into the ServiceLayer : 现在,您可以根据需要配置此模拟,并将其传递给ServiceLayer

ServiceLayer serviceLayer = new ServiceLayer(mocked);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM