Groovy 定义Spock模拟行为
我正在写我的第一个Spock测试,并阅读了上面的文档,但在一些项目上仍然没有看到“穿越树木的森林” 我有一个类,Groovy 定义Spock模拟行为,groovy,spock,Groovy,Spock,我正在写我的第一个Spock测试,并阅读了上面的文档,但在一些项目上仍然没有看到“穿越树木的森林” 我有一个类,MyRealm,它为我的应用程序执行身份验证。它有两个依赖项,AuthService和ShiroAdapter。前者我想嘲笑,后者我想保持现状(如果可能的话)。这是因为AuthService实际上建立了到LDAP的后端连接,所以我想模拟它。但是ShiroAdapter只定义了几个实用程序方法,将我的对象转换为apacheshiro安全对象(主体、权限等)。所以它可以不被模仿(我认为)
MyRealm
,它为我的应用程序执行身份验证。它有两个依赖项,AuthService
和ShiroAdapter
。前者我想嘲笑,后者我想保持现状(如果可能的话)。这是因为AuthService
实际上建立了到LDAP的后端连接,所以我想模拟它。但是ShiroAdapter
只定义了几个实用程序方法,将我的对象转换为apacheshiro安全对象(主体、权限等)。所以它可以不被模仿(我认为)
类MyRealmSpec扩展了规范{
我的王国
def设置(){
AuthService AuthService=Mock(AuthService)
//配置“authService”mock非常接近,检查抛出的异常类型的一种简单快捷的方法是将异常
类放在括号中。例如:
def "authenticate throws ShiroException whenever auth fails"() {
when:
realm.authenticate('invalid_username', 'invalid_password')
then:
thrown(ShiroException)
}
您还需要模拟LDAP服务调用本身并模拟异常或失败的登录
def "authenticate throws ShiroException whenever auth fails"() {
setup:
String invalidUserName = 'invalid_username'
String invalidPassword = 'invalid_password'
when:
realm.authenticate(invalidUserName, invalidPassword)
then:
1 * authService.doAuth(invalidUserName, invalidPassword) >> returnClosure
thrown(ShiroException)
where:
returnClosure << [{throw new ShiroException()}, { false }]
}
您可能会对几个不同的行为对象感兴趣
- 存根-您只定义返回的内容
MyObject obj = Stub{method >> null}
- mock-定义返回的内容和/或调用方法的次数
MyObject obj = Mock {1..3 methodCall >> false}
- Spies-它创建您的对象,但您可以作为模拟重写特定方法(并且您的重写仍然可以调用原始代码)
听起来你需要一个存根,但是你可以使用一个没有任何问题的mock。我提到了spy,因为如果你的对象是自立的(将来),它是一个救生圈
注:在上述测试中,此测试
模拟对返回值的计算(测试测试)
调用authenticate和doAuth()之间发生的任何代码
希望这就是你想要的。如果没有什么。身份验证()的逻辑可以打破(它的复杂性与一个吸气剂或SET方法),这个测试主要是浪费时间。逻辑的唯一方法可以打破,如果在JVM(完全超出了这个测试的责任)出了什么差错。,或者有人在将来某个时候做了更改(好吧,即使在.authenticate()包含不可破坏的基本逻辑的巨大假设下,测试也有一些价值);确保记住测试的内容和原因。这将帮助您确定测试用例的优先级,同时找出组织/分离测试逻辑的最佳方法。谢谢@Durandal(+1)-如何实现然后标签中的“或”逻辑?我将如何改变事情以实现“和”还有逻辑?再次感谢!在子句中是隐式的,每个模拟调用或列出的条件都会按提供的顺序进行检查;我只是在其中放置或,以显示返回异常与返回布尔值的示例。您可以添加where
子句来在同一测试中同时执行这两个操作。我将更新以添加这一点你能把推荐信寄出去吗?
MyObject obj = Stub{method >> null}
MyObject obj = Mock {1..3 methodCall >> false}
MyObject obj = Spy {methodCall >> false}
obj.otherMethodCall() // Calls code like normal
obj.methodCall() // Returns false like we told it to
def "authenticate throws ShiroException whenever auth fails"() {
given:
AuthService authService = Stub(AuthService)
authService.doAuth(_,_) >> expectedError
MyRealm realm = new MyRealm(
authService: authService,
shiroAdapter: new ShiroAdapter())
when:
realm.authenticate("just enough to get", "to the doAuth method")
then:
thrown(ShiroException)
where:
expectedError << [ShiroException, /*other exceptions this method has to test*/]
}
def "authenticate throws ShiroException whenever auth fails"() {
given:
AuthService authService = Stub(AuthService)
authService.doAuth(_,_) >> { args ->
return args[0] == good && args[1] == good
}
MyRealm realm = new MyRealm(
authService: authService,
shiroAdapter: new ShiroAdapter())
expect:
realm.authenticate(username, password) == expectedAuthentication
where:
userName | password | expectedAuthentication
bad | good | false
bad | bad | false
good | good | true
}