从测试用例调用控制器时,使用自动有线组件测试控制器为空

时间:2016-10-06 09:37:01

标签: java spring junit spring-boot autowired

我有一个控制器

@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字段注释在我的测试中有效?

3 个答案:

答案 0 :(得分:3)

Spring没有自动连接你的组件导致你用 new 实例化你的Controller而不是Spring,所以Component没有实现

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);
    }
}

答案 1 :(得分:1)

使用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);
    } 
}

答案 2 :(得分:1)

使用正确的注释,可以使用MockitoJUnitRunner轻松模拟和测试@Autowired类。

通过这个,你可以做任何你需要做的单元测试的模拟对象。

这是一个快速示例,它将使用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);
    }
}