英文:
How to mock Autowired constructor dependency in groovy spock
问题
我有一个类,我正在编写Groovy测试用例。这个类具有构造函数自动装配,并调用另一个方法来初始化这些字段。
@Service
public class ServiceA {
private final PrincipalDao principalDao;
@Autowired
public ServiceA(final PrincipalDao principalDao){
this.principalDao=principalDao;
this.serviceMap = getMap();
}
private Map<> getMap() {
final List<ClassA> classAList = principalDao.findAll(); //这行返回null
}
}
这行代码 final List<ClassA> classAList = principalDao.findAll();
返回 null
,我无法在Groovy中像以下这样模拟它:
principalDao.findAll() >> list
因为它甚至在我的上述行在Groovy测试用例中被调用之前就已经被调用了。
英文:
I have a class for which i am writing groovy test case. This class has constructor autowiring and calls another method to initialise the fields.:
@Service
public class ServiceA {
private final PrincipalDao principalDao;
@Autowired
public ServiceA(final PrincipalDao principalDao){
this.principalDao=principalDao;
this.serviceMap = getMap();
}
private Map<> getMap() {
final List<ClassA> classAList = principalDao.findAll(); //this line returns null
}
}
this line final List<ClassA> classAList = principalDao.findAll();
returns null
and I cant mock it in groovy like following:
principalDao.findAll() >> list
because its called even before my above line is called in groovy test case
答案1
得分: 1
看不到你的单元测试,很难确定问题是什么,但我有时会遇到一个常见的误解,就是模拟的时机问题。
这里是一个样例代码,详细说明了我的意思。由于你的问题中缺少部分代码,我会假设其中的一些部分,但我相信这能解释我要表达的观点,希望能帮助你找到答案:
服务类:
```java
@Service
public class ServiceA{
private final PrincipalDao principalDao;
private final Map<String, String> serviceMap;
@Autowired
public ServiceA(final PrincipalDao principalDao){
this.principalDao = principalDao;
this.serviceMap = getMap();
}
private Map<String, String> getMap(){
final HashMap<String, String> stringStringHashMap = new HashMap<String, String>();
stringStringHashMap.put("hello", principalDao.khello());
return stringStringHashMap;
}
public String printServiceMap() {
return serviceMap.get("hello");
}
}
class ServiceATest extends Specification {
def "some test"() {
given:
PrincipalDao principalDao = Mock()
principalDao.khello() >> "khello" // 这里的关键是:模拟发生在实例化 ServiceA 之前
ServiceA someService = new ServiceA(principalDao)
expect:
"khello" == someService.printServiceMap()
}
}
这个单元测试会成功通过。关键在于模拟的时机。principalDao.khello() >> "khello"
发生在 new ServiceA(principalDao)
之前。
如果你不需要在单元测试中修改 serviceMap,你也可以这样做,这样你就不需要在每个单元测试中定义它:
class ServiceATest extends Specification {
@Shared
PrincipalDao principalDao = Mock()
ServiceA someService = new ServiceA(principalDao)
def setupSpec() {
principalDao.khello() >> "khello"
}
def "some test"() {
expect:
"khello" == someService.printServiceMap()
}
}
英文:
Without seeing you unit test, it's hard to tell what the issue is, but a common misconception I run into sometimes is the timing of the mock.
Here's a sample code elaborating what I mean. Since parts of the code missing from your question, going to assume some parts of it, but I'm sure it explains the point I'm making and hopefully should help you out in finding an answer:
Service class:
@Service
public class ServiceA{
private final PrincipalDao principalDao;
private final Map<String, String> serviceMap;
@Autowired
public ServiceA(final PrincipalDao principalDao){
this.principalDao = principalDao;
this.serviceMap = getMap();
}
private Map<String, String> getMap(){
final HashMap<String, String> stringStringHashMap = new HashMap<String, String>();
stringStringHashMap.put("hello", principalDao.khello());
return stringStringHashMap;
}
public String printServiceMap() {
return serviceMap.get("hello");
}
}
class ServiceATest extends Specification {
def "some test"() {
given:
PrincipalDao principalDao = Mock()
principalDao.khello() >> "khello" // this is the key here. Mocking is happening before instantiation of ServiceA
ServiceA someService = new ServiceA(principalDao)
expect:
"khello" == someService.printServiceMap()
}
}
This unit test passes successfully. The point here is the timing of the mocking. principalDao.khello() >> "khello"
happens before new ServiceA(principalDao)
.
If you don't need to modify serviceMap per unit test, you can also do this so you don't have to define it per unit test:
class ServiceATest extends Specification {
@Shared
PrincipalDao principalDao = Mock()
ServiceA someService = new ServiceA(principalDao)
def setupSpec() {
principalDao.khello() >> "khello"
}
def "some test"() {
expect:
"khello" == someService.printServiceMap()
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论