Java 如何使用顺序调用测试void函数
如果一个函数不返回一个值,但使用给定的参数来构造一些发送给顺序函数的值,那么如何测试该函数呢 比如说Java 如何使用顺序调用测试void函数,java,unit-testing,mocking,mockito,powermockito,Java,Unit Testing,Mocking,Mockito,Powermockito,如果一个函数不返回一个值,但使用给定的参数来构造一些发送给顺序函数的值,那么如何测试该函数呢 比如说 public void handleSomeEvent(String str1, String str2){ MyObject obj1 = new MyObject(); obj1.setParameterA(str1); obj2.setParameterB(str2); EventHandler.getInstance().notify(obj1) } 在上面的示
public void handleSomeEvent(String str1, String str2){
MyObject obj1 = new MyObject();
obj1.setParameterA(str1);
obj2.setParameterB(str2);
EventHandler.getInstance().notify(obj1)
}
在上面的示例中,我想验证是否使用包含str1
asparameterA
和str2
asparameter2
的对象调用了EventHandler.notify
。这可以使用一些常见的模拟框架工作(即mockito)来完成吗?您可以执行以下操作
@RunWith(PowerMockRunner.class)
@PrepareForTest({ EventHandler.class })
public class UnderTestTest {
@Test
public void testLoadUniqueOrNull() throws NKFException {
PowerMockito.mockStatic(EventHandler.class);
EventHandler handler = PowerMockito.mock(EventHandler.class);
PowerMockito.when(EventHandler.getInstance())
.thenReturn(handler);
ArgumentCaptor<MyObject> handlerArg =
ArgumentCaptor.forClass(MyObject.class);
PowerMockito.doNothing()
.when(handler)
.notify(handlerArg.capture());
new UnderTest().handleSomeEvent("test");
Assert.assertEquals(new MyObject("test"), handlerArg.getAllValues()
.get(0));
}
}
public class UnderTest {
public void handleSomeEvent(String str1) {
MyObject obj1 = new MyObject(str1);
EventHandler.getInstance()
.notify(obj1);
}
}
public class MyObject {
private final String x;
public MyObject(String x) {
this.x = x;
}
@Override
public boolean equals(Object obj) {
return ((MyObject) obj).x == x;
}
}
public class EventHandler {
private final static EventHandler e = new EventHandler();
public static EventHandler getInstance() {
return e;
}
public void notify(MyObject obj) {
// whatever
}
}
@RunWith(PowerMockRunner.class)
@PrepareForTest({EventHandler.class})
公共类测试不足{
@试验
public void testLoadUniqueOrNull()引发NKFEException{
mockStatic(EventHandler.class);
EventHandler=PowerMockito.mock(EventHandler.class);
PowerMockito.when(EventHandler.getInstance())
.然后返回(处理程序);
ArgumentCaptor handlerArg=
ArgumentCaptor.forClass(MyObject.class);
PowerMockito.doNothing()
.何时(处理人)
.notify(handleArg.capture());
新的欠测试().handleSomeEvent(“测试”);
Assert.assertEquals(新的MyObject(“测试”),handleArg.getAllValues()
.get(0));
}
}
公共类测试不足{
public void handleSomeEvent(字符串str1){
MyObject obj1=新的MyObject(str1);
EventHandler.getInstance()
.通知(obj1);
}
}
公共类MyObject{
私有最终字符串x;
公共MyObject(字符串x){
这个.x=x;
}
@凌驾
公共布尔等于(对象obj){
返回((MyObject)obj).x==x;
}
}
公共类事件处理程序{
private final static EventHandler e=new EventHandler();
公共静态EventHandler getInstance(){
返回e;
}
公共无效通知(MyObject obj){
//随便
}
}
(旁注:此快速代码旨在演示功能,而非编码中的最佳实践)如果需要验证调用的parrams,请使用Mockito的
ArgumentCaptor
见参考资料:
单元测试验证公共可观察行为,其中“公共”表示通过单元API,“行为”表示返回值和/或与依赖项通信
通过对EventHandler
对象的静态访问,您的代码具有隐藏的依赖关系。我假设您的EventHandler
类包含Java singelton模式。这是我们大多数人从一开始就有的
您不应该使用PowerMock屈服于这种糟糕的设计
更好的方法是将EventHandler
对象作为构造函数参数传递给测试代码,如下所示:
class MyTestedClass{
private final EventHandler eventHandler;
class MyTestedClass(EventHandler eventHandler){
this.eventHandler=eventHandler;
}
public void handleSomeEvent(String str1, String str2){
MyObject obj1 = new MyObject();
obj1.setParameterA(str1);
obj2.setParameterB(str2);
eventHandler.notify(obj1)
}
}
然后使您的EventHandler
成为可以继承的普通类。(至少从类声明中删除final
关键字)
然后,您可以使用普通Mockito将EventHandler
对象替换为测试双精度,并验证您的代码是否与该测试双精度通信:
class MyTestedClassTest{
@Rule public MockitoRule mockitoRule = MockitoJUnit.rule();
@Mock private EventHandler eventHandler; // ignores the private constructor
class MyTestedClass(EventHandler eventHandler){
this.eventHandler=eventHandler;
}
@Test
public void notifiesEventHandlerWithDTO(String str1, String str2){
new UnderTest(eventHandler).handleSomeEvent("test1","test2");
ArgumentCaptor<MyObject> handlerArg = ArgumentCaptor.forClass(MyObject.class);
verify(eventHandler).notify(handlerArg.capture());
assertThat("parameter A passed to object",
handlerArg.getValue().getParameterA(),
equalTo("test1"));
assertThat("parameter B passed to object",
handlerArg.getValue().getParameterB(),
equalTo("test2"));
}
}
类MyTestedClassTest{
@规则public MockitoRule MockitoRule=MockitoJUnit.Rule();
@Mock private EventHandler EventHandler;//忽略私有构造函数
类MyTestedClass(EventHandler EventHandler){
this.eventHandler=eventHandler;
}
@试验
public void notifiedSeventhandlerWithDTO(字符串str1,字符串str2){
新的欠测试(eventHandler).handleSomeEvent(“test1”、“test2”);
ArgumentCaptor handlerArg=ArgumentCaptor.forClass(MyObject.class);
验证(eventHandler).notify(handlerArg.capture());
assertThat(“传递给对象的参数A”,
handlerArg.getValue().getParameterA(),
equalTo(“测试1”);
assertThat(“传递给对象的参数B”,
handlerArg.getValue().getParameterB(),
equalTo(“test2”);
}
}
编写本文时,您认为实际测试的内容可能重复?基本上你要测试的就是setter的工作。在这种情况下,EventHandler
是冗余的。您也可以断言obj1.getParamA().equals(str1)
etc@Lino-请重新阅读这两个线程,这不是同一个问题。@ABR我的观点是,这不是单元测试。您正在同时测试MyObject
和EventHandler
,而这两者都可以(也应该)独立测试。用mockMyObject测试EventHandler
。使用getter测试MyObject
(如果你真的认为测试setter有价值的话,我不这么认为)。工作起来很有魅力!不过,不需要重写equals,handlerArg.getAllValues().get(0)EventHandler接收到的已退役MyObject,然后可以分别断言其属性(即str1和str2)。谢谢虽然你的答案在技术上是正确的,但它指导OP写作。我们最好让她写可靠的代码。。。