我正在编写单元测试来测试 REST API 端点。我使用 MockMvc 来处理 API 测试,使用 @InjectMocks 来加载端点,使用 @Mock 来模拟服务层。以下是片段。
图书控制器
@RestController
@RequestMapping( path="api/v1/book")
public class BookController {
private final BookService bookService;
@Autowired
public BookController (BookService bookService){
this.bookService = bookService;
}
@GetMapping
public List<Book> getBooks() {
return bookService.getAllBook();
}
}
预订服务
@Service
public class BookService {
private final BookRepository bookRepository;
@Autowired
public BookService(BookRepository bookRepository) {
this.bookRepository = bookRepository;
}
public List<Book> getAllBook() {
return bookRepository.findAll();
}
}
**图书存储库**
@Repository
public interface BookRepository extends JpaRepository<Book, Long> {
List<Book> findAll();
}
测试类
@ExtendWith(MockitoExtension.class)
public class BookControllerTest {
private MockMvc mockMvc;
@InjectMocks
private BookController bookController;
@Mock
private BookService bookService;
@BeforeEach
public void setup() {
MockitoAnnotations.initMocks(this);
mockMvc = MockMvcBuilders.standaloneSetup(bookController).build();
}
@Test
public void getAllRecords_success() throws Exception {
List<Book> records = Arrays.asList(record1, record2, record3);
Mockito.when(bookService.getAllBook()).thenReturn(records);
MvcResult result = mockMvc.perform(MockMvcRequestBuilders
.get("/api/v1/book")
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andDo(print())
.andReturn();
}
}
当我运行测试时,我得到了 UnnecessaryStubbingException。 MvcResult result 变量具有空块而不是三本书的块(records)。 所以,我相信原因是我可能不太了解如何使用 Mockito。你能指出我正确的方向吗?
SpringBoot版本为3.2.1。
非常感谢!
================================
更新#1
我发现如果我像这样改变控制器:
@RestController
@RequestMapping( path="api/v1/book")
public class BookController {
// private final BookService bookService;
BookService bookService;
// @Autowired
// public BookController (BookService bookService){
// this.bookService = bookService;
// }
@GetMapping
public List<Book> getBooks(){
return bookService.getAllBooks();
}
}
然后模拟起作用了并且MvcResult结果变量有大量的三本书(记录)。任何人都可以解释如何解决这个问题,因为使用更新的控制器,spring 应用程序在通过邮递员发送“/api/v1/book”端点上的 get 请求时返回 500 代码。控制台中有:
NullPointerException:无法调用“mypackage.BookService.getAllBooks()”,因为“this.bookService”为空
您正在初始化模拟两次:
MockitoExtension
(内部调用 initMocks
/ openMocks
)initMocks
如果将模拟注入到最终字段,则双重初始化会失败
检查这个例子:
interface Foo {
}
class Bar {
final Foo foo;
Bar(Foo foo) {
this.foo = foo;
}
}
@ExtendWith(MockitoExtension.class)
public class InitMocksTest {
@InjectMocks Bar bar;
@Mock Foo foo;
@BeforeEach
void setup() {
System.out.println("bar: " + defaultToString(bar));
System.out.println("foo: " + defaultToString(foo));
System.out.println("bar.foo: " + defaultToString(bar.foo));
System.out.println();
MockitoAnnotations.openMocks(this);
System.out.println("bar: " + defaultToString(bar));
System.out.println("foo: " + defaultToString(foo));
System.out.println("bar.foo: " + defaultToString(bar.foo));
}
public static String defaultToString(Object o) {
return o.getClass().getName() + "@" + Integer.toHexString(o.hashCode());
}
@Test
void dummy() {
}
}
输出:
bar: com.so.examples.mockito.Bar@5d332969
foo: com.so.examples.mockito.Foo$MockitoMock$v4JhQAjO@6ca320ab
bar.foo: com.so.examples.mockito.Foo$MockitoMock$v4JhQAjO@6ca320ab
bar: com.so.examples.mockito.Bar@5d332969
foo: com.so.examples.mockito.Foo$MockitoMock$v4JhQAjO@1e34c607
bar.foo: com.so.examples.mockito.Foo$MockitoMock$v4JhQAjO@6ca320ab
第二次初始化后观察: