[英]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.