使用 spock 中的依赖项测试服务

Test service from with dependencies in spock

我正在使用 kotlin 和 spring 项目,现在我正在尝试测试一些服务,它有一些依赖性,我遇到了一些问题,以便获得成功测试。也许我的设计不够好,而且我在尝试从间谍对象调用方法时遇到问题,我遇到了问题:无法在基于接口的模拟对象上调用真实方法 'getClubhouseFor'。这是我的代码,你能告诉我我做错了什么吗?

提前致谢!!!! 这是我的代码:

import com.espn.csemobile.espnapp.models.UID
import com.espn.csemobile.espnapp.models.clubhouse.*
import com.espn.csemobile.espnapp.services.clubhouse.AutomatedClubhouseService
import com.espn.csemobile.espnapp.services.clubhouse.ClubhouseService
import com.espn.csemobile.espnapp.services.clubhouse.StaticClubhouseService
import com.espn.csemobile.espnapp.services.clubhouse.contexts.ClubhouseContext
import com.espn.csemobile.espnapp.services.core.CoreService
import rx.Single
import spock.lang.Specification

class ClubhouseServiceImplTest extends Specification {


    StaticClubhouseService staticClubhouseService = GroovyStub()
    AutomatedClubhouseService automatedClubhouseService = GroovyStub()
    CoreService coreService =  GroovyStub()
    ClubhouseContext clubhouseContext = GroovyMock()
    Clubhouse clubHouse
    ClubhouseLogo clubhouseLogo
    ClubhouseService spy = GroovySpy(ClubhouseService)

    void setup() {
        clubhouseLogo = new ClubhouseLogo("http://www.google.com", true)
        clubHouse = new Clubhouse(new UID(), "summaryType", ClubhouseType.League, new ClubhouseLayout(), "summaryName", "MLB", clubhouseLogo, "http://www.google.com", "liveSportProp",new ArrayList<Integer>(), new ArrayList<ClubhouseSection>(),new ArrayList<ClubhouseAction>(), new HashMap<String, String>())
    }



    def "GetClubhouseFor"() {
        given:
        staticClubhouseService.getClubhouseFor(clubhouseContext) >> buildClubHouseMockService()
        // The idea here is to get different responses it depends on the class of call.
        automatedClubhouseService.getClubhouseFor(clubhouseContext ) >> buildClubHouseMockService()
        spy.getClubhouseFor(clubhouseContext) >> spy.getClubhouseFor(clubhouseContext)
        when:
        def actual = spy.getClubhouseFor(clubhouseContext)
        then:
        actual != null
    }

    def buildClubHouseMockService(){
        return Single.just(clubHouse)
    }
}

接下来是参与测试的类:

import com.espn.csemobile.espnapp.models.clubhouse.*
import com.espn.csemobile.espnapp.services.clubhouse.contexts.ClubhouseContext
import com.espn.csemobile.espnapp.services.core.CoreService
import org.springframework.context.annotation.Primary
import org.springframework.context.annotation.ScopedProxyMode
import org.springframework.stereotype.Service
import org.springframework.web.context.annotation.RequestScope
import rx.Single

interface ClubhouseService {
    fun getClubhouseFor(context: ClubhouseContext): Single<Clubhouse?>
}

@Service
@RequestScope(proxyMode = ScopedProxyMode.NO)
@Primary
class ClubhouseServiceImpl(private val clubhouseContext: ClubhouseContext,
                        private var staticClubhouseService: StaticClubhouseService,
                       private var automatedClubhouseService: AutomatedClubhouseService,
                       private val coreService: CoreService?): ClubhouseService {

    override fun getClubhouseFor(context: ClubhouseContext): Single<Clubhouse?> {
        return staticClubhouseService.getClubhouseFor(clubhouseContext).flatMap { clubhouse ->
            if (clubhouse != null) return@flatMap Single.just(clubhouse)

            return@flatMap automatedClubhouseService.getClubhouseFor(clubhouseContext)
        }
    }
}

嗯,首先 GroovySpyGroovyStub 对 Java 或 Kotlin classes 没有意义,因为 Groovy 的特殊功能模拟仅适用于 Groovy classes。所以不要指望能够以这种方式模拟构造函数或静态方法,如果这是使用的原因的话。这也记录在案 here:

When Should Groovy Mocks be Favored over Regular Mocks? Groovy mocks should be used when the code under specification is written in Groovy and some of the unique Groovy mock features are needed. When called from Java code, Groovy mocks will behave like regular mocks. Note that it isn’t necessary to use a Groovy mock merely because the code under specification and/or mocked type is written in Groovy. Unless you have a concrete reason to use a Groovy mock, prefer a regular mock.

至于你的间谍问题,你不能在接口类型上使用间谍。这记录在案 here:

A spy is always based on a real object. Hence you must provide a class type rather than an interface type, along with any constructor arguments for the type.

因此,您要么切换到 Mock 或 Stub,这两者都适用于接口类型,要么您改为监视实现 class。无论如何,我的主要建议是先阅读文档,然后尝试使用像 Spock 这样的新工具。我的印象是您以前没有使用过 Spock,但当然我可能是错的。