在Springboot中如何为使用其他服务的服务编写测试?
How do I write a test for a service that uses other services in Springboot?
我有一个 BookManagementService
,它使用其他三个服务的 @Autowired
实现,就像这样
@Service
public class BookManagementService {
private final BookRepo repo;
private final BookItemRepo itemRepo;
private final BookEditionRepo editionRepo;
// the below services are the ones I want to mock in the test.
@Autowired AuthorService authorService;
@Autowired YearService yearService;
@Autowired GenreService genreService;
static String position = "1000";
public BookManagementService(BookRepo repo, BookItemRepo itemRepo, BookEditionRepo editionRepo,
YearService yearService) {
this.repo = repo;
this.itemRepo = itemRepo;
this.editionRepo = editionRepo;
}
// Rest of the methods that perform the business logic.
}
那么如何在 BookManagementServiceTest 中模拟上述服务及其存储库?
当测试开始 运行 并到达 yearService 层时,它会抛出 NullPointerEXception,因为它收到的年份是 null
BookManagementServiceTest
@SpringBootTest
@ExtendWith(MockitoExtension.class)
class BookManagementServiceTest {
// Injects the needed services
@InjectMocks private BookManagementService service;
@InjectMocks private YearService yearService;
@InjectMocks private GenreService genreService;
@InjectMocks private AuthorService authorService;
// Mock the needed repos
@Mock private BookItemRepo repoItem;
@Mock private BookEditionRepo repoEdition;
@Mock private BookRepo repo;
// External repo
@Mock private BookYearRepo yearRepo;
@Mock private GenreRepo genreRepo;
@Mock private AuthorRepo authorRepo;
@BeforeEach
void setUp() {
// instantiate the injected services
service = new BookManagementService(repo, repoItem, repoEdition, yearService);
yearService = new YearService(yearRepo);
genreService = new GenreService(genreRepo);
authorService = new AuthorService(authorRepo);
// setting the needed variables
// calling when.thenReturn for all the repos like I would in a normal single class test.
lenient().when(yearRepo.findByYear("2006")).thenReturn(year);
lenient().when(yearRepo.save(year)).thenReturn(year);
lenient().when(repoItem.save(item)).thenReturn(item);
lenient().when(yearService.create("2006", edition)).thenReturn(year);
lenient().when(repoEdition.save(edition)).thenReturn(edition);
lenient().when(repo.save(book)).thenReturn(book);
}
// Tests
}
你只需要同时模拟所有相关服务。
以此为例,假设您想测试一个 ItemService class,它具有 ItemRepositoy 和 AuthService 自动装配。
ItemService.java
@Service
public class ItemService {
@Autowired
private ItemRepository itemRepository;
@Autowired
private AuthService authService;
public Item fetchItem() {
return new Item(1, "name", 10, 100);
}
public List<Item> fetchItems() {
List<Item> items = itemRepository.findAll();
Boolean isValidItems = authService.checkItems();
if (isValidItems) items.forEach((item) -> item.setValue(item.getPrice() * item.getQuantity()));
return items;
}
}
Item.java
@Entity
public class Item {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String name;
private Integer price;
private Integer quantity;
// getters, setters and constructors...
}
AuthService.java
@Service
public class AuthService {
public Boolean checkItems() {
return true;
}
}
ItemRepository.java
public interface ItemRepository extends JpaRepository<Item, Integer> {
}
ItemServiceTest.java
@ExtendWith(MockitoExtension.class)
public class ItemServiceTest {
@InjectMocks
private ItemService itemServiceMock;
@Mock
private ItemRepository itemRepositoryMock;
@Mock
private AuthService authServiceMock;
@Test
public void fetchItems_basic() {
// arrange
List<Item> items = Arrays.asList(new Item(1, "first", 10, 100), new Item(2, "second", 20, 200));
Integer expectedResultFirst = 1000;
Integer expectedResultSecond = 4000;
when(itemRepositoryMock.findAll()).thenReturn(items);
when(authServiceMock.checkItems()).thenReturn(true);
// act
List<Item> actualResult = itemServiceMock.fetchItems();
// assert
assertEquals(expectedResultFirst, actualResult.get(0).getValue());
assertEquals(expectedResultSecond, actualResult.get(1).getValue());
}
}
如果您不模拟自动装配的 classes 并按照您的预期设置 when().thenReturn(),您将始终得到 NullPointException。
我有一个 BookManagementService
,它使用其他三个服务的 @Autowired
实现,就像这样
@Service
public class BookManagementService {
private final BookRepo repo;
private final BookItemRepo itemRepo;
private final BookEditionRepo editionRepo;
// the below services are the ones I want to mock in the test.
@Autowired AuthorService authorService;
@Autowired YearService yearService;
@Autowired GenreService genreService;
static String position = "1000";
public BookManagementService(BookRepo repo, BookItemRepo itemRepo, BookEditionRepo editionRepo,
YearService yearService) {
this.repo = repo;
this.itemRepo = itemRepo;
this.editionRepo = editionRepo;
}
// Rest of the methods that perform the business logic.
}
那么如何在 BookManagementServiceTest 中模拟上述服务及其存储库?
当测试开始 运行 并到达 yearService 层时,它会抛出 NullPointerEXception,因为它收到的年份是 null
BookManagementServiceTest
@SpringBootTest
@ExtendWith(MockitoExtension.class)
class BookManagementServiceTest {
// Injects the needed services
@InjectMocks private BookManagementService service;
@InjectMocks private YearService yearService;
@InjectMocks private GenreService genreService;
@InjectMocks private AuthorService authorService;
// Mock the needed repos
@Mock private BookItemRepo repoItem;
@Mock private BookEditionRepo repoEdition;
@Mock private BookRepo repo;
// External repo
@Mock private BookYearRepo yearRepo;
@Mock private GenreRepo genreRepo;
@Mock private AuthorRepo authorRepo;
@BeforeEach
void setUp() {
// instantiate the injected services
service = new BookManagementService(repo, repoItem, repoEdition, yearService);
yearService = new YearService(yearRepo);
genreService = new GenreService(genreRepo);
authorService = new AuthorService(authorRepo);
// setting the needed variables
// calling when.thenReturn for all the repos like I would in a normal single class test.
lenient().when(yearRepo.findByYear("2006")).thenReturn(year);
lenient().when(yearRepo.save(year)).thenReturn(year);
lenient().when(repoItem.save(item)).thenReturn(item);
lenient().when(yearService.create("2006", edition)).thenReturn(year);
lenient().when(repoEdition.save(edition)).thenReturn(edition);
lenient().when(repo.save(book)).thenReturn(book);
}
// Tests
}
你只需要同时模拟所有相关服务。
以此为例,假设您想测试一个 ItemService class,它具有 ItemRepositoy 和 AuthService 自动装配。
ItemService.java
@Service
public class ItemService {
@Autowired
private ItemRepository itemRepository;
@Autowired
private AuthService authService;
public Item fetchItem() {
return new Item(1, "name", 10, 100);
}
public List<Item> fetchItems() {
List<Item> items = itemRepository.findAll();
Boolean isValidItems = authService.checkItems();
if (isValidItems) items.forEach((item) -> item.setValue(item.getPrice() * item.getQuantity()));
return items;
}
}
Item.java
@Entity
public class Item {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String name;
private Integer price;
private Integer quantity;
// getters, setters and constructors...
}
AuthService.java
@Service
public class AuthService {
public Boolean checkItems() {
return true;
}
}
ItemRepository.java
public interface ItemRepository extends JpaRepository<Item, Integer> {
}
ItemServiceTest.java
@ExtendWith(MockitoExtension.class)
public class ItemServiceTest {
@InjectMocks
private ItemService itemServiceMock;
@Mock
private ItemRepository itemRepositoryMock;
@Mock
private AuthService authServiceMock;
@Test
public void fetchItems_basic() {
// arrange
List<Item> items = Arrays.asList(new Item(1, "first", 10, 100), new Item(2, "second", 20, 200));
Integer expectedResultFirst = 1000;
Integer expectedResultSecond = 4000;
when(itemRepositoryMock.findAll()).thenReturn(items);
when(authServiceMock.checkItems()).thenReturn(true);
// act
List<Item> actualResult = itemServiceMock.fetchItems();
// assert
assertEquals(expectedResultFirst, actualResult.get(0).getValue());
assertEquals(expectedResultSecond, actualResult.get(1).getValue());
}
}
如果您不模拟自动装配的 classes 并按照您的预期设置 when().thenReturn(),您将始终得到 NullPointException。