如何使用spock跳过一些内部void方法

问题描述 投票:0回答:1

代码:

public class A{
    public void method(User user){
        String name = user.getName();
        if("Tom".equals(name)){
            method1(user);
        }else{
            method2(user);
        }
    }
}

我想使用spock编写一个关于A#method()的测试。正如你所看到的,当我测试method()时,我不关心method1()或method2()的执行,我只想验证这两个方法在某些情况下是否会被调用。 我的测试代码:

@RunWith(PowerMockRunner.class)
@PowerMockRunnerDelegate(Sputnik.class)
class ASpec extends Specification {
   
    def "method"(){
        given:
        def process = new A()

        expect:
        process.method(input as User)

        where:
        input                || _
        new User(name:"Tom") || _
    }
}

我发现method1()确实执行了,但我认为单元测试的意义只是验证过程是否正确,所以我不希望method1()实际执行,而只是调用。 我该怎么办?

附注 我也用间谍:

@RunWith(PowerMockRunner.class)
@PowerMockRunnerDelegate(Sputnik.class)
class ASpec extends Specification {

    def "method"(){
        given:
        A process = Spy()

        expect:
        process.method(input as User)

        where:
        input                || _
        new User(name:"Tom") || _
    }
}

但是method1()也执行了。

java unit-testing groovy spock spy
1个回答
0
投票

Leonard 是完全正确的:在 >99% 的正常单元测试中

  • 你不要嘲笑或监视被测试的班级,
  • 您测试的是行为,而不是类的内部运作。

你想要的在技术上是可能的,但如果有必要的话,它通常是一种代码味道。为了便于论证,让我们假设您的测试类如下所示:

class A {
  void method(User user) {
    if ("Tom" == user.name)
      method1(user)
    else
      method2(user)
  }

  void method1(User user) {
    println "method1, doing something expensive & slow with $user.name"
  }

  void method2(User user) {
    println "method2, doing something expensive & slow with $user.name"
  }
}
class User {
  String name
}

现在你可以这样测试:

import spock.lang.Specification
import spock.lang.Unroll

class ATest extends Specification {
  @Unroll("user #user.name")
  def "expensive calculation (no mocks)"() {
    given:
    def process = new A()

    expect:
    process.method(user)

    where:
    user << [new User(name: "Tom"), new User(name: "Tina")]
  }

  @Unroll("user #user.name")
  def "expensive calculation (spy)"() {
    given:
    A process = Spy() {
      method1(_) >> null
      method2(_) >> null
    }

    expect:
    process.method(user)

    where:
    user << [new User(name: "Tom"), new User(name: "Tina")]
  }
}

在第一个测试中,您将看到被调用方法的日志输出,而在第二个测试中您将看不到,因为这两个方法已被删除。默认情况下,如果您不更改间谍程序的行为,间谍程序会调用原始方法。

Leonard 还表示,如果辅助方法所做的事情不是被测试类的核心职责,那么您应该重构。让我们假设,我们这里有这个案例。然后你可以像这样重构和测试:

class B {
  ExpensiveCalculation calculation

  void method(User user) {
    if ("Tom" == user.name)
      calculation.method1(user)
    else
      calculation.method2(user)
  }
}
class ExpensiveCalculation {
  void method1(User user) {
    println "method1, doing something expensive & slow with $user.name"
  }

  void method2(User user) {
    println "method2, doing something expensive & slow with $user.name"
  }
}
  @Unroll("user #user.name")
  def "expensive calculation (factored out, mocked)"() {
    given:
    def process = new B(calculation: Mock(ExpensiveCalculation))

    expect:
    process.method(user)

    where:
    user << [new User(name: "Tom"), new User(name: "Tina")]
  }

Groovy Web Console 中尝试,然后单击“结果”选项卡查看测试报告。

© www.soinside.com 2019 - 2024. All rights reserved.