Java @从单元测试中使用@Service实例调用方法时,存储库实例为null
我的目标是为这些单元测试使用内存中的数据库,这些相关性如下所示:Java @从单元测试中使用@Service实例调用方法时,存储库实例为null,java,spring,spring-boot,unit-testing,jpa,Java,Spring,Spring Boot,Unit Testing,Jpa,我的目标是为这些单元测试使用内存中的数据库,这些相关性如下所示: implementation("org.springframework.boot:spring-boot-starter-data-jpa") runtimeOnly("com.h2database:h2") 因此,存储库实例实际上与数据库交互,我不只是模拟返回值 问题是,当我运行单元测试时,服务实例中的存储库实例是null 为什么呢?我是否缺少初始化存储库实例的单元测试类上的注释 这是运
implementation("org.springframework.boot:spring-boot-starter-data-jpa")
runtimeOnly("com.h2database:h2")
因此,存储库实例实际上与数据库交互,我不只是模拟返回值
问题是,当我运行单元测试时,服务实例中的存储库实例是null
为什么呢?我是否缺少初始化存储库实例的单元测试类上的注释
这是运行我的单元测试时的控制台输出:
null
java.lang.NullPointerException
at com.my.MyService.findAll(MyService.java:20)
at com.my.MyTest.testMy(MyTest.java:23)
我的单元测试类:
public class MyTest {
@MockBean
MyRepository myRepository;
@Test
void testMy() {
MyService myService = new MyService();
int size = myService.findAll().size();
Assertions.assertEquals(0, size);
}
}
我的服务级别:
@Service
public class MyService {
@Autowired
MyRepository myRepository;
public List<MyEntity> findAll() {
System.out.println(myRepository); // null
return (List<MyEntity>) myRepository.findAll(); // throws NullPointerException
}
@Transactional
public MyEntity create(MyEntity myEntity) {
myRepository.save(myEntity);
return myEntity;
}
}
要使用
@MockBean
注释,必须使用SpringRunner来运行测试。在测试类顶部使用@RunWith
注释并通过SpringRunner.class
@RunWith(SpringRunner.class)
public class MyTest {
@MockBean
MyRepository myRepository;
@Test
void testMy() {
MyService myService = new MyService();
int size = myService.findAll().size();
Assertions.assertEquals(0, size);
}
}
要使用
@MockBean
注释,必须使用SpringRunner来运行测试。在测试类顶部使用@RunWith
注释并通过SpringRunner.class
@RunWith(SpringRunner.class)
public class MyTest {
@MockBean
MyRepository myRepository;
@Test
void testMy() {
MyService myService = new MyService();
int size = myService.findAll().size();
Assertions.assertEquals(0, size);
}
}
我相信您希望编写一个集成测试。在这里,您可以删除MockBean注释,只需自动连接存储库。此外,与SpringRunner课程一起跑步
@RunWith(SpringRunner.class)
public class MyTest {
@Autowired
MyRepository myRepository;
@Autowired
MyService myService
@Test
void testMy() {
int size = myService.findAll().size();
Assertions.assertEquals(0, size);
}
}
这应该行得通我相信您希望编写一个集成测试。在这里,您可以删除MockBean注释,只需自动连接存储库。此外,与SpringRunner课程一起跑步
@RunWith(SpringRunner.class)
public class MyTest {
@Autowired
MyRepository myRepository;
@Autowired
MyService myService
@Test
void testMy() {
int size = myService.findAll().size();
Assertions.assertEquals(0, size);
}
}
这应该行得通这里的问题是您的服务实现。当您运行整个应用程序时,使用
@Autowired
注入依赖项会起作用,但它不允许您在需要时注入自定义依赖项,测试就是一个很好的例子
将服务实现更改为:
@Service
public class MyService {
private MyRepository myRepository;
public MyService(MyRepository myRepository){
this.myRepository = myRepository;
}
public List<MyEntity> findAll() {
System.out.println(myRepository); // null
return (List<MyEntity>) myRepository.findAll(); // throws NullPointerException
}
@Transactional
public MyEntity create(MyEntity myEntity) {
myRepository.save(myEntity);
return myEntity;
}
}
注意,我已将@MockBean
替换为@Mock
,因为前面的注释用于将模拟bean注入到spring上下文中,如果您正在进行单元测试,则不需要这样做。如果您想启动spring上下文(我不建议您这样做),您需要使用@SpringBootTest
或其他一些可用的选项来配置测试类。这将把您的测试转换为集成测试
PD:如果不向
myRepository.findAll()
提供模拟,此测试将不起作用。Mockito的默认行为是返回null,但您希望它返回0,因此您需要执行类似于given(myRepository.findAll())的操作。willReturn(0)
这里的问题是您的服务实现。当您运行整个应用程序时,使用@Autowired
注入依赖项会起作用,但它不允许您在需要时注入自定义依赖项,测试就是一个很好的例子
将服务实现更改为:
@Service
public class MyService {
private MyRepository myRepository;
public MyService(MyRepository myRepository){
this.myRepository = myRepository;
}
public List<MyEntity> findAll() {
System.out.println(myRepository); // null
return (List<MyEntity>) myRepository.findAll(); // throws NullPointerException
}
@Transactional
public MyEntity create(MyEntity myEntity) {
myRepository.save(myEntity);
return myEntity;
}
}
注意,我已将@MockBean
替换为@Mock
,因为前面的注释用于将模拟bean注入到spring上下文中,如果您正在进行单元测试,则不需要这样做。如果您想启动spring上下文(我不建议您这样做),您需要使用@SpringBootTest
或其他一些可用的选项来配置测试类。这将把您的测试转换为集成测试
PD:如果不向myRepository.findAll()
提供模拟,此测试将不起作用。Mockito的默认行为是返回null,但您希望它返回0,因此您需要执行类似于given(myRepository.findAll())的操作。willReturn(0)
为什么呢?我是否缺少初始化存储库实例的单元测试类上的注释
基本上是的:)
您需要通过使用@springbootest
另一个问题是手动创建MyService
对象。
这样,SpringBoot就没有机会为您注入任何Bean。您可以通过简单地将MyService
注入Testclass来解决这个问题。您的代码应该如下所示:
@SpringBootTest
public class MyTest {
@Autowired
private MyService myService;
@Test
void testMy() {
int size = myService.findAll().size();
assertEquals(0, size);
}
}
为什么呢?我是否缺少初始化存储库实例的单元测试类上的注释
基本上是的:)
您需要通过使用@springbootest
另一个问题是手动创建MyService
对象。
这样,SpringBoot就没有机会为您注入任何Bean。您可以通过简单地将MyService
注入Testclass来解决这个问题。您的代码应该如下所示:
@SpringBootTest
public class MyTest {
@Autowired
private MyService myService;
@Test
void testMy() {
int size = myService.findAll().size();
assertEquals(0, size);
}
}
谢谢这里的信息。但我确实概述了我希望做一个集成样式的测试,这样我就不会模拟
myRepository.findAll()
的响应。我希望对内存数据库进行适当的查询,以返回0/null的结果。。因为我还没有在数据库中插入任何对象。谢谢这里的信息。但我确实概述了我希望做一个集成样式的测试,这样我就不会模拟myRepository.findAll()
的响应。我希望对内存数据库进行适当的查询,以返回0/null的结果。。因为我还没有在数据库中插入任何对象。