我正在编写我的第一个Spock测试,并在嘲弄互动上阅读文档,但仍然没有在一些项目上看到“穿过树的森林”。
我有一个类MyRealm,它为我的应用程序执行身份验证。它有两个依赖项,AuthService和ShiroAdapter。前者是我想嘲笑的,后者是我想要离开的(如果有可能的话)。这是因为AuthService实际上建立了到LDAP的后端连接,所以我想对它进行模拟。但是ShiroAdapter只定义了几个实用工具方法,它们将我的对象转换为Apache安全对象(主体、权限等)。所以它可以不被嘲笑(我的)。
class MyRealmSpec extends Specification {
MyRealm realm
def setup() {
AuthService authService = Mock(AuthService)
// configure 'authService' mock <-- ?????
ShiroAdapter shiroAdapter = new ShiroAdapter()
realm = new MyRealm(authService: authService,
shiroAdapter: shiroAdapter)
}
def "authenticate throws ShiroException whenever auth fails"() {
when:
realm.authenticate('invalid_username', 'invalid_password')
then:
Throwable throwable = thrown()
ShiroException.isAssignableFrom(throwable)
}
}我相信我是非常接近,但正在努力配置模拟的行为方式,我希望它的测试。Spock文档(上面链接的)似乎只记录了如何验证一个模拟方法被调用的次数。我对此不感兴趣。
在这里,MyRealm#authenticate(String,String)调用了引擎盖下的AuthService#doAuth(String,String)。因此,我需要我的模拟AuthService实例简单地返回false (指示失败的auth),或者在发生意外事件时抛出ServiceFaulException。
我有什么想法可以完成这件事吗?
发布于 2015-10-10 14:46:40
您非常接近,检查抛出的异常类型的一种简单、快捷的方法是将Exception类放在括号中。例如:
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 }]
}请注意,您需要在模拟语句上使用参数匹配,或者使用通配符匹配。
要匹配任何字符串,可以使用下划线语法:
1 * authService.doAuth(_, _) >> false发布于 2015-10-12 00:18:50
您可能对几个不同的行为对象感兴趣。
听起来你需要一个存根,但你可以使用一个模拟,没有任何问题。我提到间谍,因为如果你的目标在将来是自食其力的话,它是一种拯救生命的工具。
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
}注意上面的测试,这个测试..。
希望这就是你想要的。如果.authenticate()的逻辑中没有任何东西可以破坏(它的复杂性与getter或setter方法一样),那么这个测试主要是浪费时间。逻辑崩溃的唯一方法是,如果JVM中出了问题(这完全超出了这个测试的责任范围),或者将来某个时候有人做了一些更改(好,即使在.authenticate()包含不可打破的基本逻辑的巨大假设下,测试也有一定的价值)。我漫不经心的离题(非常抱歉);一定要记住测试的内容和原因。它将帮助您对测试用例进行优先排序,并同时制定组织/分离测试逻辑的最佳方法。
https://stackoverflow.com/questions/33052855
复制相似问题