在我的测试BusinessFlow
类中,我有一些私有服务字段和一个带有java String
类型的私有字段。
在我的测试课上,我有
@RunWith(MockitoJUnitRunner.class)
public class BusinessFlowTest {
// How can I mock or spy this?
private String code = "codeValue";
@Mock
private Service1Api service1;
@Mock
private Service2Api service2;
@InjectMocks
private BusinessFlow flow;
...
}
@InjectMocks
和@Mock
注释极大地创建了模拟并注入了服务字段。但是,由于 Mockito 不允许为final
类创建模拟,我如何为code
字段创建模拟?
我看到的一个选项是使用CharSequence
接口而不是String
字段类型,但它需要更改BusinessFlow
类的代码,我不喜欢这个想法。
更新:类BusinessFlow
是这样定义的
@Service
public class BusinessFlow {
@Autowired
@Qualifier(value = "clientCode")
private String code;
@Autowired
private Service1Api service1;
@Autowired
private Service2Api service2;
...
}
由于某种原因,我们不使用弹簧集成测试功能,也不想在不同类型的注射(例如CTOR注射(中返工BusinessFlow
模仿外部依赖项,这些依赖项要么太过禁止,无法在测试上下文中启动,要么不需要这样做。 你模拟服务和DAO层接入点之类的东西,以确保你所做的只是一个单元测试。
您要做的是为您运行的每个测试更改此字段的值,而与模拟无关。 请记住 - 这些模拟是外部依赖项。 您可以轻松控制*进入类的字符串。
有关测试中的示例:
@Test
public void testWithFoo() {
// given
flow.setValue("foo");
// when
// invoke a pertinent method
// then
// observe results
}
*:如果你不能,这是一个重构的好机会。
模拟数据对象或具有可重复或无状态行为的简单类(如JDK提供的类(是不明智的。
由于您遇到的确切问题,不鼓励现场注入。
但是,如果您选择忽略这种公认的智慧,Spring 确实为此目的提供了一个实用程序类:org.springframework.test.util.ReflectionTestUtils
。
有了这个,你可以注入到你的类中:
BusinessFlow flow = new BusinessFlow();
ReflectionTestUtils.setField(flow, "code", "testcode");
ReflectionTestUtils.setField(flow, "service1", mockService);
当然,你可以直接使用Java Reflection API实现同样的事情,但这稍微方便一些。
被认为是一种非常糟糕的做法,可以模拟java.lang
包下的任何内容。此外,不建议在 Spring 中使用现场注入。控制Spring code
最便宜的方法是重构类以使用构造函数注入。
@Service
public class BusinessFlow {
private String code;
private Service1Api service1;
private Service2Api service2;
@Autowired
public BusinessFlow(@Qualifier(value = "clientCode") String code,
Service1Api service1,
Service2Api service2) {
this.code = code;
this.service1 = service1;
this.service2 = service2;
}
}
这不会花费你任何费用,你不必改变BusinessFlow
类的客户端(只要它由 Spring 管理(。现在,您可以在不使用 Spring 测试功能的情况下控制注入到类中的数据。
Service1Api service1 = mock(Service1Api.class);
Service2Api service2 = mock(Service2Api.class);
BusinessFlow businessFlow = new BusinessFlow("codeValue", service1, service2);
使用 Apache Commons 反射方法来初始化测试类中的字符串值,如下所示
FieldUtils.writeField(classObject, "variableName", "value", true(;