从测试用例调用控制器时,使用自动连线组件测试控制器为空
Testing a controller with an auto wired component is null when calling the controller from a test case
我有一个控制器
@RestController
public class Create {
@Autowired
private ComponentThatDoesSomething something;
@RequestMapping("/greeting")
public String call() {
something.updateCounter();
return "Hello World " + something.getCounter();
}
}
我有那个控制器的组件
@Component
public class ComponentThatDoesSomething {
private int counter = 0;
public void updateCounter () {
counter++;
}
public int getCounter() {
return counter;
}
}
我也对我的控制器进行了测试。
@RunWith(SpringRunner.class)
@SpringBootTest
public class ForumsApplicationTests {
@Test
public void contextLoads() {
Create subject = new Create();
subject.call();
subject.call();
assertEquals(subject.call(), "Hello World 2");
}
}
控制器调用something.updateCounter()
时测试失败。我得到一个 NullPointerException
。虽然我知道可以将 @Autowired
添加到构造函数中,但我想知道是否可以使用 @Autowired
字段来执行此操作。如何确保 @Autowired
字段注释在我的测试中有效?
使用 Mockito 并注入您创建的模拟。我更喜欢构造函数注入:
@RestController
public class Create {
private ComponentThatDoesSomething something;
@Autowired
public Create(ComponentThatDoesSomething c) {
this.something = c;
}
}
不要在 Junit 测试中使用 Spring。
public CreateTest {
private Create create;
@Before
public void setUp() {
ComponentThatDoesSomething c = Mockito.mock(ComponentThatDoesSomething .class);
this.create = new Create(c);
}
}
Spring 不会自动连接您的组件,因为您使用 new 而非 Spring 实例化您的控制器,因此组件未实例化
SpringMockMvc 测试检查是否正确:
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest
public class CreateTest {
@Autowired
private WebApplicationContext context;
private MockMvc mvc;
@Before
public void setup() {
mvc = MockMvcBuilders
.webAppContextSetup(context)
.build();
}
@Test
public void testCall() throws Exception {
//increment first time
this.mvc.perform(get("/greeting"))
.andExpect(status().isOk());
//increment secont time and get response to check
String contentAsString = this.mvc.perform(get("/greeting"))
.andExpect(status().isOk()).andReturn()
.getResponse().getContentAsString();
assertEquals("Hello World 2", contentAsString);
}
}
可以使用带有正确注释的 MockitoJUnitRunner 轻松模拟和测试 @Autowired class。
有了这个,您可以为单元测试对模拟对象做任何您需要做的事情。
这是一个简单示例,它将使用来自 ComponentThatDoesSomething 的模拟数据测试 Create 方法调用。
@RunWith(MockitoJUnitRunner.class)
public class CreateTest {
@InjectMocks
Create create;
@Mock
ComponentThatDoesSomething componentThatDoesSomething;
@Test
public void testCallWithCounterOf4() {
when(componentThatDoesSomething.getCounter()).thenReturn(4);
String result = create.call();
assertEquals("Hello World 4", result);
}
}
我有一个控制器
@RestController
public class Create {
@Autowired
private ComponentThatDoesSomething something;
@RequestMapping("/greeting")
public String call() {
something.updateCounter();
return "Hello World " + something.getCounter();
}
}
我有那个控制器的组件
@Component
public class ComponentThatDoesSomething {
private int counter = 0;
public void updateCounter () {
counter++;
}
public int getCounter() {
return counter;
}
}
我也对我的控制器进行了测试。
@RunWith(SpringRunner.class)
@SpringBootTest
public class ForumsApplicationTests {
@Test
public void contextLoads() {
Create subject = new Create();
subject.call();
subject.call();
assertEquals(subject.call(), "Hello World 2");
}
}
控制器调用something.updateCounter()
时测试失败。我得到一个 NullPointerException
。虽然我知道可以将 @Autowired
添加到构造函数中,但我想知道是否可以使用 @Autowired
字段来执行此操作。如何确保 @Autowired
字段注释在我的测试中有效?
使用 Mockito 并注入您创建的模拟。我更喜欢构造函数注入:
@RestController
public class Create {
private ComponentThatDoesSomething something;
@Autowired
public Create(ComponentThatDoesSomething c) {
this.something = c;
}
}
不要在 Junit 测试中使用 Spring。
public CreateTest {
private Create create;
@Before
public void setUp() {
ComponentThatDoesSomething c = Mockito.mock(ComponentThatDoesSomething .class);
this.create = new Create(c);
}
}
Spring 不会自动连接您的组件,因为您使用 new 而非 Spring 实例化您的控制器,因此组件未实例化
SpringMockMvc 测试检查是否正确:
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest
public class CreateTest {
@Autowired
private WebApplicationContext context;
private MockMvc mvc;
@Before
public void setup() {
mvc = MockMvcBuilders
.webAppContextSetup(context)
.build();
}
@Test
public void testCall() throws Exception {
//increment first time
this.mvc.perform(get("/greeting"))
.andExpect(status().isOk());
//increment secont time and get response to check
String contentAsString = this.mvc.perform(get("/greeting"))
.andExpect(status().isOk()).andReturn()
.getResponse().getContentAsString();
assertEquals("Hello World 2", contentAsString);
}
}
可以使用带有正确注释的 MockitoJUnitRunner 轻松模拟和测试 @Autowired class。
有了这个,您可以为单元测试对模拟对象做任何您需要做的事情。
这是一个简单示例,它将使用来自 ComponentThatDoesSomething 的模拟数据测试 Create 方法调用。
@RunWith(MockitoJUnitRunner.class)
public class CreateTest {
@InjectMocks
Create create;
@Mock
ComponentThatDoesSomething componentThatDoesSomething;
@Test
public void testCallWithCounterOf4() {
when(componentThatDoesSomething.getCounter()).thenReturn(4);
String result = create.call();
assertEquals("Hello World 4", result);
}
}