全部
感谢您的帮助。我对Mockito还是很陌生,如果我有一个Service类,一个控制器类(通过传递Map参数使用该服务),该如何模拟该服务方法?
Helloworldservice.java
package service;
import java.util.Map;
public class Helloworldservice {
public String greeting() {
return "Hello, World";
}
public String greetingSB(Map<String, String> sb) {
return "Hello," + sb.get("name");
}
}
Helloworldcontroller.java
package controller;
import java.util.HashMap;
import java.util.Map;
import service.Helloworldservice;
public class Helloworldcontroller {
private Helloworldservice hservice;
public Helloworldcontroller() {
// TODO Auto-generated constructor stub
hservice = new Helloworldservice();
}
public String sayHello() {
return hservice.greeting();
}
public String sayHelloSB() {
Map<String, String> sb = new HashMap<String, String>();
sb.put("name", "somebody");
return hservice.greetingSB(sb);
}
}
HelloworldcontrollerTest.java
package unit.controller;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnitRunner;
import controller.Helloworldcontroller;
import service.Helloworldservice;
@RunWith(MockitoJUnitRunner.class)
public class HelloworldcontrollerTest {
@InjectMocks
private Helloworldcontroller hcontroller;
private Helloworldservice hservice = new Helloworldservice();
@Mock
private Helloworldservice hservice_mock;
@Before
public void setup() {
hservice_mock = Mockito.spy(hservice);
/** I am not sure how to mock here for that param sb
Mockito.when(hservice_mock.greetingSB(.......))
.thenReturn("Hello, somebody");
**/
}
@Test
public void testGreeting() {
String h = hcontroller.sayHelloSB();
Assert.assertEquals(h, "Hello, sombody!!!");
}
}
服务总是返回null,我不确定是什么错误。
答案 0 :(得分:1)
您的示例代码有点不正确,因为它可以正常工作而无需任何模拟。
public class HelloworldcontrollerTest {
private Helloworldcontroller hcontroller = new Helloworldcontroller();
@Test
public void testGreeting() {
String h = hcontroller.sayHelloSB();
Assert.assertEquals(h, "Hello,somebody");
}
}
无论如何,可能只是一个示例。
嘲讽的问题在于这一行
hservice_mock = Mockito.spy(hservice);
首先,让Mockito创建模拟(@Mock Helloworldservice hservice_mock
)并将其注入到控制器(@InjectMocks Helloworldcontroller hcontroller
)中,然后自己创建间谍(hservice_mock = Mockito.spy(hservice)
)您尝试设置期望值(when(hservice_mock.greetingSB(...))
)。为间谍建立期望值需要不同的方法调用链,因此当前会发生NullPointerException
(请参见Important gotcha on spying real objects!)。即使可以使用,也不会影响已经注入的模拟。
这将按预期工作:
@RunWith(MockitoJUnitRunner.class)
public class HelloworldcontrollerTest {
@InjectMocks
private Helloworldcontroller hcontroller = new Helloworldcontroller();
@Mock
private Helloworldservice hservice_mock;
@Before
public void setup() {
Mockito.when(hservice_mock.greetingSB(any(Map.class)))
.thenReturn("Hello, somebody!!!");
}
@Test
public void testGreeting() {
String h = hcontroller.sayHelloSB();
Assert.assertEquals(h, "Hello, somebody!!!");
}
}
关于测试设置的其他一些评论:
Helloworldcontroller
依赖于Helloworldservice
。与其在构造函数中创建实例,不如考虑使用构造函数依赖注入。您的示例代码可以工作,但是如果变得更复杂,事情就会失去控制。想想数据库访问。@InjectMocks
是代码气味的标志,表示要测试的代码存在更深层的问题。尽量避免。assertEquals
中assertEquals(h, "Hello, sombody!!!")
的第一个参数是期望值,然后是实际值。听起来不是很重要,但是会影响断言违反错误消息。 让我们解决这些问题,看看我们如何改进代码。
首先,使用构造函数注入。
public class Helloworldcontroller {
private final Helloworldservice hservice;
public Helloworldcontroller(Helloworldservice hservice) {
this.hservice = hservice;
}
public String sayHello() {
return hservice.greeting();
}
public String sayHelloSB() {
Map<String, String> sb = new HashMap<String, String>();
sb.put("name", "somebody");
return hservice.greetingSB(sb);
}
}
测试代码现在变为
@RunWith(MockitoJUnitRunner.class)
public class HelloworldcontrollerTest {
private Helloworldcontroller hcontroller;
@Mock
private Helloworldservice hservice;
@Before
public void setup() {
hcontroller = new Helloworldcontroller(hservice);
Mockito.when(hservice.greetingSB(any(Map.class)))
.thenReturn("Hello, somebody!!!");
}
@Test
public void testGreeting() {
Assert.assertEquals("Hello, somebody!!!", hcontroller.sayHelloSB());
}
}
答案 1 :(得分:1)
测试类中有几个地方需要固定,如数字1、2所示...
@RunWith(MockitoJUnitRunner.class)
public class HelloworldcontrollerTest {
@InjectMocks
private Helloworldcontroller hcontroller;
private Helloworldservice hservice = new Helloworldservice();
@Mock
private Helloworldservice hservice_mock;
@Before
public void setup() {
// 1. Comment out this line, because you've already created a mock instance using @Mock
// hservice_mock = Mockito.spy(hservice);
/** I am not sure how to mock here for that param sb
Mockito.when(hservice_mock.greetingSB(.......))
.thenReturn("Hello, somebody");
**/
}
@Test
public void testGreeting() {
// 2. This's why program output null. If you create an entire mock(not a real mock or a partial mock) object, then you should give the specific expectation for the method.
Mockito.when(hservice_mock.greetingSB(Mockito.any())).thenReturn("Hello world!!");
String h = hcontroller.sayHelloSB();
Assert.assertEquals(h, "Hello, sombody!!!");
}
}
关于完整模拟和部分模拟之间的区别,您可以参考this link。
总而言之,使用模拟的基本步骤是: