假设我有多个登录的Geb / Spock测试。例如:
@Stepwise
Class AddNewPictureSpec extends GebSpec {
def "User at login page"() {
given: "User beings from login page"
to LoginPage
}
def "User gets redirected to Main page"() {
given: "User at Login page"
at LoginPage
when: "User signs in"
signIn "username", "pw"
to MainPage
then:
at MainPage
def "other test sequences follow...."() {
}
}
另一个具有完全相同启动顺序的测试规范:
@Stepwise
Class EditPictureSpec extends GebSpec {
def "User at login page"() {
given: "User beings from login page"
to LoginPage
}
def "User gets redirected to Main page"() {
given: "User at Login page"
at LoginPage
when: "User signs in"
signIn "username", "pw"
to MainPage
then:
at MainPage
def "other test sequences follow...."() {
}
}
如何重构/提取常用登录“步骤”,以便我没有重复的代码?还是我错误地写了我的测试?感谢。
答案 0 :(得分:6)
我认为'geb'方法是使用modules。
您可以创建如下的登录模块:
class LoginModule extends Module {
static content = {
loginForm {$("form")}
loginButton {$("input", value: "Sign in")}
}
void login(String username, String password = "Passw0rd!") {
loginForm.j_username = username
loginForm.j_password = password
loginButton.click()
}
}
将其包含在LoginPage
:
class LoginPage extends Page {
static url = "login/auth"
static at = {title == "My Grails Application"}
static content = {
loginModule { module LoginModule }
}
}
然后在测试中,您可以引用模块的login
方法:
@Stepwise
class EditPictureSpec extends GebSpec {
def setupSpec() {
to LoginPage
loginModule.login(loginUsername)
}
def "some test"() {
...
}
}
答案 1 :(得分:2)
一种可能性是使用一个Spec来验证完全按原样写出的实际登录行为(例如LoginSpec
)。对于在进行实际测试之前需要登录的其他规范,您可以在LoginPage
中的方法后面抽象整个登录过程。就像你现在使用singIn
一样。
如果你有很多需要登录才能真正开始测试他们打算测试的功能,那么一次又一次地通过浏览器执行登录步骤会花费很多时间。
另一种方法是创建一个特定的控制器,该控制器仅在开发/测试环境中加载并提供登录操作。
因此,您可以直接转到网址/my-app/testLogin/auth?username=username
,而不是完成所有步骤(转到页面,输入名称,输入密码......)。
下面是我们在Grails + Spring Security设置中如何做到这一点的示例。我们还在该控制器中捆绑了其他实用程序方法,这些方法用于设置多个规范,否则在浏览器中需要多次点击,例如改变界面语言。
// Example TestLoginController when using the Spring Security plugin
class TestLoginController {
def auth = { String userName, String startPage = 'dashboard' ->
// Block the dev login functionality in production environments
// Can also be done with filter, ...
Environment.executeForCurrentEnvironment {
production {
render(status: HttpServletResponse.SC_NOT_FOUND)
return
}
}
def endUser = getYourEndUserDataByUsername()
if (endUser) {
// Logout existing user
new SecurityContextLogoutHandler().logout(request, null, null)
// Authenticate the user
UserDetails userDetails = new User(endUser)
def authenticationToken = new UsernamePasswordAuthenticationToken(userDetails, userDetails.password, userDetails.authorities)
SecurityContextHolder.context.setAuthentication(authenticationToken)
// Bind the security context to the (new) session
session.SPRING_SECURITY_CONTEXT = SecurityContextHolder.context
redirect(action: "index", controller: startPage)
}
}
答案 2 :(得分:2)
您可以创建一个登录方法并将其放入BaseSpec(您也将创建),然后在测试中扩展。例如:
class BaseSpec extends GebReportingSpec {
def login(name, pw) {
to LoginPage
// login code here...
}
}
由于您正在使用@StepWise,我假设您每个规范都登录一次,因此请使用setupSpec()...
Class AddNewPictureSpec extends BaseSpec {
def setupSpec() {
login("username", "password")
}
}
答案 3 :(得分:1)
正确的解决方案是在geb页面上创建封装常用功能的方法:
class LoginPage extends Page {
static url = "login/auth"
static at = {title == "Login"}
static content = {
username { $("#user") }
password { $("#password") }
}
def login(String email, String passwd) {
emailInput.value(email)
passwordInput.value(passwd)
passwordInput << Keys.ENTER
}
}
然后你的测试看起来像这样:
@Stepwise
class ThingSpec extends GebSpec {
def setupSpec() {
to LoginPage
page.login("user", "pass")
}
def "some test"() {
...
}
}
从OOP角度来看,这是最佳解决方案,因为登录过程仅适用于登录页面。使用模块是没有意义的,因为没有其他页面有登录框(除非它有,否则模块是有意义的。)
使用继承也没有意义,你最终会得到一堆无组织的方法和类名,比如“BaseSpec”,bleh。