【问题标题】:How to use spock to test a service with real transactions in Grails application?如何在 Grails 应用程序中使用 spock 测试具有真实事务的服务?
【发布时间】:2014-11-21 07:24:17
【问题描述】:

我正在使用 Grails 2.4.4 并希望在我的项目中应用 spock 测试。

以下是会员服务

@Transactional
class MemberService {

    def lastMember = null

    def login (userId, password) {

        def member = Member.findByLoginEmail(userId)
        if(!member) return LoginResult.NO_SUCH_MEMBER
        if (member.isLocked) return LoginResult.MEMBER_IS_LOCKED

        log.debug("member.password is [${member.passwd}], input password is [${password}]")

        if (!member.passwd.equals(password)) return LoginResult.PASSWORD_ERROR

        switch(member.validateResult) {
            case "FAILED":
                return LoginResult.VAILDATE_FAILED
            case "WAIT":
                return LoginResult.WAIT_VALIDATE
        }

        member.lasLoginTime = new Timestamp(System.currentTimeMillis())
        member.lastLoginPlatform = "WEB"
        member.loginFailCount = 0
        member.save()
        lastMember = member
        return LoginResult.SUCCESS
    }

    enum LoginResult {
        SUCCESS,
        NO_SUCH_MEMBER,
        PASSWORD_ERROR,
        MEMBER_IS_LOCKED,
        VAILDATE_FAILED,
        WAIT_VALIDATE
    }

    enum ValidateResult {
        SUCCESS,
        FAILED,
        WAIT
    }
}

MemberServiceSpec如下:

@TestFor(MemberService)
@Mock(Member)
class MemberServiceSpec extends Specification {
    def memberService

    def setup() {
        memberService = new MemberService()
    }

    void "test something"() {

        when:
            println "service is ${service}"
            def result = memberService.login("aa@mymail.com", "123456")
            println "result is ${result}"
        then:
            result == MemberService.LoginResult.SUCCESS
    }
}

测试结果如下:

Testing started at 15:15 ...
|Loading Grails 2.4.4
|Configuring classpath
.
|Environment set to test
....................................
|Running without daemon...
..........................................
|Compiling 1 source files
.
|Running 2 unit tests...|Running 2 unit tests... 1 of 2
--Output from test something--
1. setup
service is cusine_market.MemberService@54c425b1
Enter MemberService.login----------------userId=[aa@mymail.com]
result is NO_SUCH_MEMBER
Failure:  |
test something(cusine_market.MemberServiceSpec)
 |
Condition not satisfied:
result == MemberService.LoginResult.SUCCESS
|      |
|      false
NO_SUCH_MEMBER
    at cusine_market.MemberServiceSpec.test something(MemberServiceSpec.groovy:32)
Condition not satisfied:

result == MemberService.LoginResult.SUCCESS
|      |
|      false
NO_SUCH_MEMBER

Condition not satisfied:

result == MemberService.LoginResult.SUCCESS
|      |
|      false
NO_SUCH_MEMBER

    at cusine_market.MemberServiceSpec.test something(MemberServiceSpec.groovy:32)

|Completed 1 unit test, 1 failed in 0m 6s
.Tests FAILED 

我确认该用户存在于数据库中。

谁能告诉我为什么 MemberService 在数据库中找不到用户“aa@mymail.com”?我也尝试了下面的行

    memberService = Mock(MemberService);

结果是一样的。但是,如果我运行应用程序,该服务会找到用户。

【问题讨论】:

    标签: grails testing service transactions spock


    【解决方案1】:

    嘲讽

    在您的测试中,您正在测试MemberService,这意味着您不需要模拟它。只需通过service 参考即可。

    测试数据

    这看起来像单元测试,而不是集成测试。所以它根本不使用你的数据库。

    您需要做的是在测试中手动创建Member 实例。您在 @Mock 注释中有它,这很好。

    现在,创建对象,最好在 given 块中:

    void "test something"() {
        given:
            new Member(loginEmail: 'aa@mymail.com', password: '123456', ...).save(failOnError: true, flush: true)
    
        when:
            println "service is ${service}"
            def result = service.login("aa@mymail.com", "123456")
            println "result is ${result}"
        then:
            result == MemberService.LoginResult.SUCCESS
    }
    

    我添加了failOnError: true 以确保对象已实际创建。您 - 当然 - 需要在 Member 构造函数中提供所有必需的属性,并确保您提供的数据与您提供给 login 方法的数据相对应。

    此外,您需要确保 Member 对象的初始化方式满足您想要到达的路径。比如要达到LoginResult.SUCCES状态,需要将member.isLocked设置为false等。

    奖金

    当您进行此测试时,您可能需要查看Build Test Data Plugin。它使创建测试数据(例如您的 Member 对象)变得更加容易。

    【讨论】:

    • 很高兴能帮上忙!快乐的Spocking! :)
    猜你喜欢
    • 2013-09-09
    • 2012-03-29
    • 1970-01-01
    • 1970-01-01
    • 2011-07-11
    • 2016-06-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多