You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在Spock框架中何时使用Mock与Stub?兼析Grails文档相关表述

Mock vs. Stub in Spock: When to Use Which?

Great questions—let’s break this down clearly, since mixing up mocks and stubs is a common pitfall in testing.

When to Use a Mock in Spock

Mocks are all about verifying interactions between your test subject and its collaborators. You use a mock when you need to prove that the subject is talking to its dependencies the right way—not just that it gets a result, but that it makes the correct calls with the right arguments, at the right time, and the right number of times.

Examples of mock scenarios:

  • You’re testing a UserService and want to ensure it calls UserRepository.save(user) exactly once after validating the user.
  • You need to confirm that a NotificationSender is never called if the input data is invalid.
  • You want to verify that a PaymentProcessor receives a charge request with the exact amount and currency specified.

In Spock, you’d use Mock() and add interaction checks in the then: block, like:

def "user service saves valid user once"() {
    given:
    def repo = Mock(UserRepository)
    def service = new UserService(repo: repo)
    def user = new User(name: "Alice")

    when:
    service.createUser(user)

    then:
    1 * repo.save(user)
}

When to Use a Stub in Spock

Stubs, on the other hand, are about providing canned responses to let your test subject do its job. You don’t care about how the subject interacts with the stub—you just need the stub to return specific data (or throw exceptions) so you can test how the subject behaves in response to those scenarios.

Examples of stub scenarios:

  • You’re testing that a ProductService returns an "out of stock" message when the InventoryClient reports zero quantity.
  • You want to verify that your OrderProcessor handles a timeout error from the ShippingAPI by retrying once.
  • You need to simulate a UserRepository returning a null user to test how your AuthService handles invalid login attempts.

In Spock, you’d use Stub() and define canned responses in the given: or when: block, like:

def "product service returns out of stock message when inventory is zero"() {
    given:
    def inventoryClient = Stub(InventoryClient)
    inventoryClient.getStock(123) >> 0
    def service = new ProductService(inventoryClient: inventoryClient)

    when:
    def result = service.checkStock(123)

    then:
    result == "Out of stock"
}

Breaking Down the Grails Documentation Quote

Let’s unpack that Grails docs statement to make it concrete:

If the test is concerned with proving that the test subject interacts with a collaborator in a particular way, use a mock. If the fact that a collaborator behaves in a certain way exposes a particular behavior in the test subject the outcome of that behavior is what you are testing, use a stub.

  • The first part aligns perfectly with mock use cases: your test’s core goal is to confirm interaction details (method calls, arguments, frequency). The test passes only if those interactions happen exactly as expected.
  • The second part describes stub use cases: your test focuses on how the subject responds to the collaborator’s behavior. The test’s success depends on the subject’s outcome (like returning the right message or handling an error correctly), not on the specifics of how it called the collaborator.

In short: Mocks verify interactions; stubs provide data to test behavior.

内容的提问来源于stack exchange,提问作者rihabe berrich

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 06:33:19