如何在 Spring 引导单元测试中使用依赖注入?
How to use Dependency Injection with Spring Boot Unit Testing?
是否可以使用 Spring Boot 将依赖注入与单元测试结合使用?对于集成测试 @SpringBootTest
启动整个应用程序上下文和容器服务。但是是否可以在单元测试粒度上启用依赖注入功能?
这是示例代码
@ExtendWith(SpringExtension.class)
public class MyServiceTest {
@MockBean
private MyRepository repo;
@Autowired
private MyService service; // <-- this is null
@Test
void getData() {
MyEntity e1 = new MyEntity("hello");
MyEntity e2 = new MyEntity("world");
Mockito.when(repo.findAll()).thenReturn(Arrays.asList(e1, e2));
List<String> data = service.getData();
assertEquals(2, data.size());
}
}
@Service
public class MyService {
private final MyRepository repo; // <-- this is null
public MyService(MyRepository repo) {
this.repo = repo;
}
public List<String> getData() {
return repo.findAll().stream()
.map(MyEntity::getData)
.collect(Collectors.toList());
}
}
或者我是否应该将 SUT(服务 class)作为 POJO 进行管理并手动注入模拟的依赖项?我想保持快速测试但尽量减少样板代码。
您还没有为 MyRepository
添加 @Autowired
服务
服务Class
@Service
public class MyService {
private final MyRepository repo; // <-- this is null
@Autowired
public MyService(MyRepository repo) {
this.repo = repo;
}
public List<String> getData() {
return repo.findAll().stream()
.map(MyEntity::getData)
.collect(Collectors.toList());
}
}
服务测试Class
@ExtendWith(MockitoExtension.class)
public class MyServiceTest {
@Mock
private MyRepository repo;
@InjectMocks
private MyService service;
@Test
void getData() {
MyEntity e1 = new MyEntity("hello");
MyEntity e2 = new MyEntity("world");
Mockito.when(repo.findAll()).thenReturn(Arrays.asList(e1, e2));
List<String> data = service.getData();
assertEquals(2, data.size());
}
}
正如评论中提到的@M.Deinum,单元测试不应该使用依赖注入。使用 Mockito(和 Junit5)模拟 MyRepository
并注入 MyService
:
@ExtendWith(MockitoExtension.class)
public class MyServiceTest {
@InjectMocks
private MyService service;
@Mock
private MyRepository repo;
@Test
void getData() {
MyEntity e1 = new MyEntity("hello");
MyEntity e2 = new MyEntity("world");
Mockito.when(repo.findAll()).thenReturn(Arrays.asList(e1, e2));
List<String> data = service.getData();
assertEquals(2, data.size());
}
}
如果要测试存储库,请使用 @DataJpaTest
。来自 docs:
Using this annotation will disable full auto-configuration and instead
apply only configuration relevant to JPA tests.
@DataJpaTest
public class MyRepositorTest {
@Autowired
// This is injected by @DataJpaTest as in-memory database
private MyRepository repo;
@Test
void testCount() {
repo.save(new MyEntity("hello"));
repo.save(new MyEntity("world"));
assertEquals(2, repo.count());
}
}
总而言之,建议的方法是使用 Mockito(或类似库)测试模拟存储库层的服务层,并使用 @DataJpaTest
.
测试存储库层
是否可以使用 Spring Boot 将依赖注入与单元测试结合使用?对于集成测试 @SpringBootTest
启动整个应用程序上下文和容器服务。但是是否可以在单元测试粒度上启用依赖注入功能?
这是示例代码
@ExtendWith(SpringExtension.class)
public class MyServiceTest {
@MockBean
private MyRepository repo;
@Autowired
private MyService service; // <-- this is null
@Test
void getData() {
MyEntity e1 = new MyEntity("hello");
MyEntity e2 = new MyEntity("world");
Mockito.when(repo.findAll()).thenReturn(Arrays.asList(e1, e2));
List<String> data = service.getData();
assertEquals(2, data.size());
}
}
@Service
public class MyService {
private final MyRepository repo; // <-- this is null
public MyService(MyRepository repo) {
this.repo = repo;
}
public List<String> getData() {
return repo.findAll().stream()
.map(MyEntity::getData)
.collect(Collectors.toList());
}
}
或者我是否应该将 SUT(服务 class)作为 POJO 进行管理并手动注入模拟的依赖项?我想保持快速测试但尽量减少样板代码。
您还没有为 MyRepository
@Autowired
服务
服务Class
@Service
public class MyService {
private final MyRepository repo; // <-- this is null
@Autowired
public MyService(MyRepository repo) {
this.repo = repo;
}
public List<String> getData() {
return repo.findAll().stream()
.map(MyEntity::getData)
.collect(Collectors.toList());
}
}
服务测试Class
@ExtendWith(MockitoExtension.class)
public class MyServiceTest {
@Mock
private MyRepository repo;
@InjectMocks
private MyService service;
@Test
void getData() {
MyEntity e1 = new MyEntity("hello");
MyEntity e2 = new MyEntity("world");
Mockito.when(repo.findAll()).thenReturn(Arrays.asList(e1, e2));
List<String> data = service.getData();
assertEquals(2, data.size());
}
}
正如评论中提到的@M.Deinum,单元测试不应该使用依赖注入。使用 Mockito(和 Junit5)模拟 MyRepository
并注入 MyService
:
@ExtendWith(MockitoExtension.class)
public class MyServiceTest {
@InjectMocks
private MyService service;
@Mock
private MyRepository repo;
@Test
void getData() {
MyEntity e1 = new MyEntity("hello");
MyEntity e2 = new MyEntity("world");
Mockito.when(repo.findAll()).thenReturn(Arrays.asList(e1, e2));
List<String> data = service.getData();
assertEquals(2, data.size());
}
}
如果要测试存储库,请使用 @DataJpaTest
。来自 docs:
Using this annotation will disable full auto-configuration and instead apply only configuration relevant to JPA tests.
@DataJpaTest
public class MyRepositorTest {
@Autowired
// This is injected by @DataJpaTest as in-memory database
private MyRepository repo;
@Test
void testCount() {
repo.save(new MyEntity("hello"));
repo.save(new MyEntity("world"));
assertEquals(2, repo.count());
}
}
总而言之,建议的方法是使用 Mockito(或类似库)测试模拟存储库层的服务层,并使用 @DataJpaTest
.