java 正确测试 Spring 服务
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/44853144/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Correctly testing a Spring service
提问by Darrel Holt
The following test fails with a NullPointerException
on the line usersRepo.save(user);
. I believe it's because when the test goes into the performProvision()
function the usersRepo
object is null
.
以下测试失败,并NullPointerException
显示为usersRepo.save(user);
。我相信这是因为当测试进入performProvision()
函数时,usersRepo
对象是null
.
However, when the web service is actually running and the endpoint for my controller is hit, everything works fine and the database is updated.
但是,当 Web 服务实际运行并且我的控制器的端点被命中时,一切正常并且数据库被更新。
Any idea why the test fails? My idea was that PAutoProvision
references the real database, whereas it should be dealing with the in-memory database so maybe there is some sort of conflict? I have also seen a lot of different examples with annotations set up differently, so I suppose that could be a problem too.
知道为什么测试失败吗?我的想法是PAutoProvision
引用真实的数据库,而它应该处理内存数据库,所以可能存在某种冲突?我也看到了很多不同的例子,注释设置不同,所以我想这也可能是一个问题。
UsersRepo extends JpaRepository where PAutoProvision is a SQL table entity.
UsersRepo 扩展了 JpaRepository,其中 PAutoProvision 是一个 SQL 表实体。
If this isn't enough information, I can provide the UsersRepo
, PAutoProvision
, and ProvisionController
classes if necessary.
如果没有足够的信息,我可以提供的UsersRepo
,PAutoProvision
以及ProvisionController
如果必要的类。
The Service:
服务:
@Service
public class ProvisionService {
@Autowired
private UsersRepo usersRepo;
public String performProvision(UserData userData) {
try {
PAutoProvision user = new PAutoProvision(userData);
usersRepo.save(user); // OOTB CRUD repository functionality of springData to update/insert record data
return String.format("Success: User %s has been added to the database", userData.getUserId());
} catch (Exception e) {
e.printStackTrace();
System.out.println(e.toString());
System.out.println("\n\n Cannot perform the provisioning of the user " + userData.getUserId() + ": \n" + e.toString() + "\n\n");
}
return "problem";
}
}
The Test:
考试:
@RunWith(SpringRunner.class)
public class ProvisionServiceTest {
private ProvisionService provisionService;
@MockBean
private UsersRepo usersRepo;
@Before
public void setUp(){
provisionService = new ProvisionService();
}
@Test
public void performProvision_shouldPass() {
UserData userData = new UserData("userid", 30, 1, "spot", 1);
try {
String result = provisionService.performProvision(userData);
assertThat(result, is(equalTo("Success: User userid has been added to the database")));
} catch (Exception e) {
e.printStackTrace();
System.out.println(e.toString());
}
}
}
EDIT 1:
编辑 1:
Adding @Autowired
and removing setUp()
method results in the following:
添加@Autowired
和删除setUp()
方法的结果如下:
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'com.autoprovision.ProvisionServiceTest': Unsatisfied dependency expressed through field 'provisionService'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.autoprovision.ProvisionService' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'com.autoprovision.ProvisionServiceTest': Unsatisfied dependency expressed through field 'provisionService'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.autoprovision.ProvisionService' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
回答by iBiber
As JB Nizet already stated, the UserRepo
mock is not injected into the provisionService instance, because the provisionService instance is created in the setUp method with new
.
正如 JB Nizet 已经说过的,UserRepo
模拟没有被注入到 provisionService 实例中,因为 provisionService 实例是在 setUp 方法中使用new
.
Your test should look like this:
您的测试应如下所示:
@RunWith(SpringRunner.class)
public class ProvisionServiceTest {
@Autowired // let Spring instantiate the instance to test
private ProvisionService provisionService;
@MockBean
private UsersRepo usersRepo;
@Test
public void performProvision_shouldPass() {
UserData userData = new UserData("userid", 30, 1, "spot", 1);
String result = provisionService.performProvision(userData);
assertThat(result, is(equalTo("Success: User userid has been added to the database")));
}
}
回答by robin850
The given answer seems useful but just in case it can help someone, testing service is not so obvious in Spring (IMHO). The SpyBean
annotation turns out to be really handy:
给定的答案似乎很有用,但以防万一它可以帮助某人,Spring 中的测试服务并不那么明显(恕我直言)。该SpyBean
注释被证明是非常方便的:
@RunWith(SpringRunner.class)
public class ProvisionServiceTest {
@SpyBean
private ProvisionService provisionService;
}
Source : Spring Boot Reference - Testing