繁体   English   中英

如何在UnitTest类中将对象传递给正在测试的类?

[英]How can I pass an object to my class under test in a UnitTest class?

我想测试一个具有“ ObjectMapper”作为实例变量的类:

public class EventTransformerImpl implements EventTransformer {


 @Inject
 private ObjectMapper objectMapper;

private String convertParametersToJson(NotificationConfig config) {
        String parametersAsJson = null;
        try {
            parametersAsJson = objectMapper.writeValueAsString(config.getOrdinaryParameters());
        } catch (IOException e) {
            logger.info("There was a problem in writing json:" + config.getParameters(), e);
            parametersAsJson = null;
        }
        return parametersAsJson;
    }
}

此类没有用于初始化“ objectMapper”的任何“设置程序”或“构造函数”(使用“ spring”进行初始化):

<bean id="objectMapper" class="com.fasterxml.jackson.databind.ObjectMapper">
    <property name="dateFormat">
        <bean class="java.text.SimpleDateFormat">
            <constructor-arg value="yyyy-MM-dd'T'HH:mm:ssZ"/>
        </bean>
    </property>
</bean>

当我想测试“ EventTransformerImpl”类时,objectMapper具有空值,如何在单元测试类中将“ objectMapper”传递给“ EventTransformerImpl”。

这是一个典型的示例,其中的模拟框架(例如Mockito )可以帮助您:

public class TestClass {
  @Mock
  private ObjectMapper objectMapper;

  @InjectMocks
  private EventTransformer eventTransformer;

  @BeforeMethod
  public void setUp() {
    eventTransformer = new EventTransformerImpl();
    MockitoAnnotations.initMocks(this);
  }  
}

在这里, @Mock@InjectMocks是框架的Mockito的部分。 魔术发生在MockitoAnnotations.initMocks(this) ,它将扫描this ,在这种情况下为TestClass ,以查找这些注释。 初始化的Mockito objectMapper作为假的,并将其注入到eventTransformer 然后,您可以使用Mockito来决定objectMapper行为。

您可以在此处阅读有关Mockito的更多信息。

同样, @BeforeMethod是一个TestNG方法,类似于JUnits @Before


但是,许多人更喜欢davidxxx提出的构造函数注入 这将使EventTransformerImpl具有哪些依赖关系更加清楚,并强制使用正确的依赖关系对其进行初始化。 这样,就无需“神奇地”(我想Mockito会在幕后使用反射)注入依赖项,只需通过调用构造函数初始化要测试的类即可。

您的类可能看起来像这样(这里使用Spring的@Autowired批注):

public class EventTransformerImpl implements EventTransformer {

  private ObjectMapper objectMapper;

  @Autowired
  public EventTransformerImpl(ObjectMapper objectMapper) {
    this.objectMapper = objectMapper;
  }

  private String convertParametersToJson(NotificationConfig config) {
    String parametersAsJson = null;
    try {
      parametersAsJson = objectMapper.writeValueAsString(config.getOrdinaryParameters());
    } catch (IOException e) {
      logger.info("There was a problem in writing json:" + config.getParameters(), e);
      parametersAsJson = null;
    }
    return parametersAsJson;
  }
}

这将减少出错的@InjectMocks ,因为使用@InjectMocks ,如果Mockito失败,则Mockito将静默忽略注入,而调用构造函数将使测试类完全控制测试的初始化。

1)一个类应该自然地可以测试:为什么不在EventTransformerImpl添加一个构造函数来注入映射器呢?

您可以在spring配置中做类似的事情:

  <bean id="EventTransformer" class="EventTransformerImpl">
      <constructor-arg ref="objectMapper"/>
   </bean>

在测试中,您可以在构造函数中使用ObjectMapper模拟的依赖关系实例化EventTransformerImpl

2)另一种解决方案是在测试方法中使用反射将字段注入被测类中。

您可以使用Spring的ReflectionTestUtils类的setField()方法来设置依赖关系,或者,如果您不使用Spring,则可以编写一个简单的实用程序方法来完成此工作:

public static final void injectValue(String fieldName, Object fieldValue, Object targetObject) {
    try {
        Field f = targetObject.getClass().getDeclaredField(fieldName);
        f.setAccessible(true);
        f.set(targetObject, fieldValue);
    } catch (Exception e) {
       // handle the exception
    }
}

为了在JUnit测试和其他对象中注入Spring依赖关系,我使用

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "classpath:testBeans.xml" })
public class TestRunner {

    @Test
    public void test1() {

您还可以提供代码内的bean初始化

@RunWith(SpringJUnit4ClassRunner.class)
@Configuration

https://www.mkyong.com/unittest/junit-spring-integration-example/了解更多

这三个答案都是好的。 因此,我不需要重复这些细节,但是我认为值得在“完整”图片上“对齐”。

如图所示, Spring具有内置的进行单元测试的方法。 您可以继续使用它。 但是,当然,这意味着您需要将业务逻辑代码更多地“耦合”到Spring框架。

因此,如果您考虑在非Spring情况下重用您的代码,那么您将发现不仅生产代码,而且单元测试都需要大量的修改才能在不使用Spring的情况下使用。

因此,在另外两个答案中,有一个优点是建议更改生产代码,以使您至少可以完全测试生产代码,而无需在此处添加对Spring的依赖。

暂无
暂无

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

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