Java 通过Mockito注入字符串
在测试Java 通过Mockito注入字符串,java,unit-testing,mockito,Java,Unit Testing,Mockito,在测试BusinessFlow的类中,我有一些私有服务字段和一个javaString类型的私有字段 在我的测试课上我有 @RunWith(MockitoJUnitRunner.class) public class BusinessFlowTest { // How can I mock or spy this? private String code = "codeValue"; @Mock private Service1Api service1; @
BusinessFlow
的类中,我有一些私有服务字段和一个javaString
类型的私有字段
在我的测试课上我有
@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;
...
}
@injectmock
和@Mock
注释极大地创建了Mock和injectservice字段。但是当Mockito不允许为final
类创建mock时,如何为code
字段创建mock
我看到的一个选项是使用CharSequence
接口而不是String
字段类型,但它需要更改BusinessFlow
类的代码,我不喜欢这种想法
更新:classBusinessFlow
的定义如下
@Service
public class BusinessFlow {
@Autowired
@Qualifier(value = "clientCode")
private String code;
@Autowired
private Service1Api service1;
@Autowired
private Service2Api service2;
...
}
出于某种原因,我们不使用Spring集成测试功能,也不想在不同类型的注入(例如,ctor注入)中返工
BusinessFlow
模拟的目的是模拟外部依赖,这些依赖要么过于禁止,无法在测试上下文中启动,要么没有必要这样做。您模拟服务和DAO层访问点,以确保您所做的只是一个单元测试
您想要做的是为您运行的每个测试更改此字段的值,独立于您的模拟。记住——这些模拟是外部依赖项。你可以很容易地控制进入课堂的字符串
有关测试中的示例:
@Test
public void testWithFoo() {
// given
flow.setValue("foo");
// when
// invoke a pertinent method
// then
// observe results
}
*:如果不能,这是一个很好的重构机会。在
java.lang
包中模拟任何东西被认为是非常糟糕的做法。
此外,不建议在春季使用现场注入。
控制Spring代码的最便宜的方法是重构类以使用构造函数注入
@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);
模拟数据对象或具有可重复或无状态行为的简单类(如JDK提供的)是不明智的
不鼓励现场注入,因为正是您遇到的问题
然而,如果您选择忽略这一公认的智慧,Spring确实为此提供了一个实用程序类:org.springframework.test.util.ReflectionTestUtils
有了它,您可以在类中注入以下内容:
BusinessFlow flow = new BusinessFlow();
ReflectionTestUtils.setField(flow, "code", "testcode");
ReflectionTestUtils.setField(flow, "service1", mockService);
当然,您可以直接使用Java反射API实现同样的功能,但这稍微方便一些。使用apache commons反射方法初始化测试类中的字符串值,如下所示
writeField(类对象,“变量名”,“值”,true) 你为什么要模仿绳子?为什么不传递一个适合您需要的值呢。@litelite因为我想用不同的code
值测试我的BusinessFlow
。那么为什么不在每次创建/使用BusinessFlow
时传递一个不同的值呢?你知道模拟和注入的区别吗?您想监视什么?@litelite原因与我无法传递服务值相同:在BusinessFlow
Spring字段注入用于注入服务和code
值。我的团队成员刚刚实现了这个想法。但我不喜欢这样:1。出于测试目的2,它需要更改源类。在一个类中引入了两种不同类型的DI:setter和field injection(请参阅我在文章中的更新)。@AndriyKryvtsun:以这种方式使用@Autowired
是不受欢迎的;您应该考虑使用基于构造函数或基于setter的注入。然而,我没有发现自己在抱怨设计的改变;我确实提到过这对于重构来说是一个很好的练习。理论上我同意你的观点,但实际上先读一下我的评论,请读一下我之前的评论。评论为什么我不想进行重构第二,我的同事们总是在争论为什么我们应该引入更复杂的重构注入,因为我们可以用更少的详细字段注入达到同样的目标(@AndriyKryvtsun当然你可以通过字段注入达到同样的目标。好吧,几乎是同样的目标。这里有一个完美的例子说明为什么使用ctor注入更好:你可以轻松地测试你的类,甚至不必使用任何模拟库。但是,你总是可以使用Spring测试功能来提供假bean,而不是真实的bean一个。@AndriyKryvtsun您也可以使用反射将值注入到您的字段中。但在这种情况下,您依赖于类的实现。这不是一个好的做法。您应该测试行为,而不是实现。Spring测试bean方法是值得的选择,因为将我的单元测试转换为涉及Spring上下文的集成测试。