如何测试是否调用了具有特定动态值的mocked logService方法?
@SpringBean
private LogService logService = Mock(LogService)
def "test if id is logged"() {
when:
createdPersonId = personService.savePerson(personRequest)
then:
1 * logService.logSavedId(_) // it works fine
1 * logService.logSavedId(createdPersonId) // it doesn't work, createdPersonId is expected to be null instead of real value
}
static class PersonService {
LogService logService
PersonRepository personRepository
int savePerson(PersonRequest personRequest) {
def id = UUID.randomUUID().toString()
PersonEntity personEntity = mapRequestToEntity(personRequest)
entity.id = id
personRepository.persist(personEntity)
logService.logSavedId(id)
return id
}
}
也许我能抓住人格?
我不想注入UUID提供程序只是为了生成UUID并在测试中模拟它。但是我可以模拟/存根个人存储库(它是由Spring注入的)。
您不能在交互中使用createdPersonId
,因为then:
块中的模拟交互实际上已转换为在时在
块之前定义。你有一个自举或母鸡对鸡蛋的问题,看看我的另一个答案。在定义该方法调用中使用的模拟的所需行为和交互时,不能使用测试中方法调用的结果。
但是,您可以这样做(对不起,我不得不推测您在问题中没有显示的依赖类):
package de.scrum_master.stackoverflow
import spock.lang.Specification
class PersonServiceTest extends Specification {
private LogService logService = Mock(LogService)
def "test if id is logged"() {
given:
def person = new Person(id: 11, name: "John Doe")
def personRequest = new PersonRequest(person: person)
def personService = new PersonService(logService: logService)
def id = personRequest.person.id
when:
def createdPersonId = personService.savePerson(personRequest)
then:
1 * logService.logSavedId(id)
createdPersonId == id
}
static class Person {
int id
String name
}
static class PersonRequest {
Person person
}
static class LogService {
void logSavedId(int id) {
println "Logged ID = $id"
}
}
static class PersonService {
LogService logService
int savePerson(PersonRequest personRequest) {
def id = personRequest.person.id
logService.logSavedId(id)
return id
}
}
}
更新:以下是如何重构应用程序以使其更具可测试性的两种变体。
在这里,我们将ID创建分解为一个受保护的方法
createId()
,然后我们可以在一个名为Spy
的部分模拟中进行剔除:
package de.scrum_master.stackoverflow.q60829903
import spock.lang.Specification
class PersonServiceTest extends Specification {
def logService = Mock(LogService)
def "test if id is logged"() {
given:
def person = new Person(name: "John Doe")
def personRequest = new PersonRequest(person: person)
and:
def personId = "012345-6789-abcdef"
def personService = Spy(PersonService) {
createId() >> personId
}
personService.logService = logService
when:
personService.savePerson(personRequest)
then:
1 * logService.logSavedId(personId)
person.id == personId
}
static class Person {
String id
String name
}
static class PersonRequest {
Person person
}
static class LogService {
void logSavedId(String id) {
println "Logged ID = $id"
}
}
static class PersonService {
LogService logService
String savePerson(PersonRequest personRequest) {
def id = createId()
personRequest.person.id = id
logService.logSavedId(id)
return id
}
protected String createId() {
return UUID.randomUUID().toString()
}
}
}
在这里,我们将ID创建分解为一个专用类
IdCreator
,该类易于模拟。它将ID创建与PersonService
分离。不需要使用像Spy(PersonService)
这样的花哨东西,一个带有注入ID创建者的普通服务实例就足够了。即使在生产使用中,也可以很容易地将UUID创建者重新用于其他对象ID,单独测试它,通过子类覆盖它,或者甚至为了不同的目的重构成具有不同实现的接口。你可能会认为这是过度工程,但我认为不是。解耦和可测试性是软件设计中必须具备的基本要素。
package de.scrum_master.stackoverflow.q60829903
import spock.lang.Specification
class PersonServiceTest extends Specification {
def logService = Mock(LogService)
def "test if id is logged"() {
given:
def person = new Person(name: "John Doe")
def personRequest = new PersonRequest(person: person)
and:
def personId = "012345-6789-abcdef"
def idCreator = Stub(IdCreator) {
createId() >> personId
}
def personService = new PersonService(logService, idCreator)
when:
personService.savePerson(personRequest)
then:
1 * logService.logSavedId(personId)
person.id == personId
}
static class Person {
String id
String name
}
static class PersonRequest {
Person person
}
static class LogService {
void logSavedId(String id) {
println "Logged ID = $id"
}
}
static class IdCreator {
String createId() {
return UUID.randomUUID().toString()
}
}
static class PersonService {
LogService logService
IdCreator idCreator
PersonService(LogService logService) {
this(logService, new IdCreator())
}
PersonService(LogService logService, IdCreator idCreator) {
this.logService = logService
this.idCreator = idCreator
}
String savePerson(PersonRequest personRequest) {
def id = idCreator.createId()
personRequest.person.id = id
logService.logSavedId(id)
return id
}
}
}
问题内容: 以下代码给出了编译错误,提示“意外运行”: 我知道,如果正常调用函数就可以获取返回值,而无需使用goroutine。或者我可以使用频道等 我的问题是为什么不能从goroutine中获取像这样的返回值。 问题答案: 严格的答案是您 可以 做到。这可能不是一个好主意。下面的代码可以做到这一点: 这将产生一个新的goroutine,它将进行计算,然后将结果分配给。问题是:您将如何使用原始go
我有一个返回< code>List的方法。现在我想知道如何正确放置< code>try/catch块。如果我将< code>return语句放在< code>try中,我会得到错误 并非所有代码路径都返回值 如果我放置在之后(就像我目前所做的那样),即使在之后,它也会返回。那么最好的方法应该是什么? 方法如下:
我正在处理一个Spring Boot java服务,该服务包含一个Camel处理器类,如下所示: 当我运行它时,我得到一个失败,声明对1*LogService.Update(_)的调用太少(0个调用)。我试着调试代码,在MyProc中,语句被命中,并且logService对象在高亮显示时(在Eclipse中)状态为“mock for type logService named$spock_shar
我想要能够让我的catch请求用户输入文件名,直到文件名有效为止,有没有人能给我一个建议,如何安排我的代码做到这一点? 导入java.io.FileNotFoundException;导入java.util.scanner; public class Requierment2{public static void main(String[]args){ }
我正在研究一个使用反射调用另一个方法的方法。然而,“其他方法”可以引发异常,我想用它的原始堆栈信息和内部异常来传播该异常。这只是因为使用反射的方法不应该处理异常,调用方应该处理异常。 下面是代码的简化版本: 该代码显然不会编译,因为Test方法(根据编译器)并不总是返回值。我可以在异常DispatchInfo之后添加一个return false。捕获,但我想知道是否有更好的方法来实现同样的目标。不
本文向大家介绍Python使用迭代器捕获Generator返回值的方法,包括了Python使用迭代器捕获Generator返回值的方法的使用技巧和注意事项,需要的朋友参考一下 本文实例讲述了Python使用迭代器捕获Generator返回值的方法。分享给大家供大家参考,具体如下: 用for循环调用generator时,发现拿不到generator的return语句的返回值。如果想要拿到返回值,必须