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



我想测试一个以"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"的"setter"或"constructor"(它是使用"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的值为null,我如何在单元测试类中将"objectMapper"传递给"EventTransformerCimpl"。

这是一个典型的例子,其中mock框架(如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初始化为mock,并将其注入到eventTransformer中。然后,您可以使用Mockito来决定objectMapper的行为方式。

你可以在这里阅读更多关于Mockito的信息。

此外,@BeforeMethod是一种TestNG方法,类似于JUnits@Before


然而,许多人更喜欢构造函数注入,正如davidxx所提出的那样。这将使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,如果注入失败,Mockito将静默地忽略注入,而调用构造函数将使测试类完全控制测试的初始化。

为了在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的依赖的情况下至少完全测试生产代码。

1)类应该是自然可测试的:为什么不在EventTransformerImpl中添加一个构造函数来注入映射程序呢

你可以在春季配置中做类似的事情:

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

相关内容

  • 没有找到相关文章

最新更新