【问题标题】:Hooks @Before and @after are called twice in the beginning钩子@Before 和@after 在开始时被调用了两次
【发布时间】:2017-08-03 12:20:07
【问题描述】:

我对自动化测试和 Cucumber 也很陌生。我写了一个简单的 cucumber-Junit 示例,包含三个场景。

我希望@Before 在每个场景开始时被调用,@After 在每个场景之后被调用。所以总共应该只执行 3 次,因为有 3 个场景。

当我运行以下步骤定义时,首先调用 @Before,然后调用 @After,然后再次调用 @Before,然后是场景 1,然后是 @After,然后是 @Before,然后是场景 2,然后@After,然后直接调用场景 3。因此分别在场景 3 之前和之后调用 @Before@After。另一方面,在执行第一个场景之前,它们会被调用两次。知道我在这里做错了什么吗?我的 Hook 项目中没有任何 .rb 文件。

我的@Before containsSystem.out.println("Setup performed"); 和我的@After 包含System.out.println("CleanUp Performed");

import cucumber.api.PendingException;
import cucumber.api.java.After;
import cucumber.api.java.Before;
import cucumber.api.java.en.Given;
import cucumber.api.java.en.Then;
import cucumber.api.java.en.When;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;

public class CalculatorSteps {
    private Calculator calculator;

    @Before
    public void setUp() {
        calculator = new Calculator();
        System.out.println("Setup Performed...");
    }

    //Scenario : add two numbers - With regular expression
    @Given("^I have a calculator$")
    public void i_have_a_calculator() {
        assertNotNull(calculator);
    }

    @When("^I add (\\d+) and (\\d+)$")
    public void i_add(int arg1, int arg2) {
        calculator.add(arg1, arg2);
    }

    @Then("^the result should be (\\d+)$")
    public void the_result_should_be(int result) {
        assertEquals(result, calculator.getResult());
    }

    //Scenario : Subtract one number from another - With regular expression

    @Given("^I have a calculatorr$")
    public void i_have_a_calculator1() throws Throwable {
        assertNotNull(calculator);
    }

    @When("^I subtract (\\d+.\\d+) from (\\d+.\\d+)$")
    public void i_subtract_from(int arg1, int arg2) {
    calculator.subtract(arg1, arg2);
    }

    @Then("^the result should be (\\d+.\\d+)$")
    public void the_result_should_be1(double result1) {
        assertEquals(result1, calculator.getresult1(), 0.5);
    } 

    @After
    public void cleanUp() {
        System.out.println("CleanUp Performed...");
    }
}

功能文件看起来像:

    Feature: Calculator
      I use Calculator instead of calculating myself

      #Scenario: Add two numbers
        #Given I have a calculator
        #When I add 2 and 3
        #Then the result should be 5

     @smokeTest
      Scenario Outline: Add two numbers
        Given I have a calculator
            When I add <num1> and <num2>
        Then the result should be <ans>

        Examples:
        | num1 | num2 | ans |
        | 2    | 3    | 5   |
        | 4    | 5    | 9   |

      @regressionTest
      Scenario: Subtract one number from another
        Given I have a calculator
        When I subtract 2.5 from 7.5
        Then the result should be 5.0

输出如下:

    Feature: Calculator
      I use Calculator instead of calculating myself
    Setup Performed...
    CleanUp Performed...
    Setup Performed...

      Scenario Outline: Add two numbers # src/test/java/cucumber/junit/maven/cucumber_jvm/maven/calculatorFeature.feature:19
        Given I have a calculator       # CalculatorSteps.i_have_a_calculator()
        When I add 2 and 3              # CalculatorSteps.i_add(int,int)
        Then the result should be 5     # CalculatorSteps.the_result_should_be(int)
    CleanUp Performed...
    Setup Performed...

      Scenario Outline: Add two numbers # src/test/java/cucumber/junit/maven/cucumber_jvm/maven/calculatorFeature.feature:20
        Given I have a calculator       # CalculatorSteps.i_have_a_calculator()
        When I add 4 and 5              # CalculatorSteps.i_add(int,int)
        Then the result should be 9     # CalculatorSteps.the_result_should_be(int)
    CleanUp Performed...

      #@regressionTest
      Scenario: Subtract one number from another # src/test/java/cucumber/junit/maven/cucumber_jvm/maven/calculatorFeature.feature:23
        Given I have a calculator                # CalculatorSteps.i_have_a_calculator()
        When I subtract 2.5 from 7.5             # CalculatorSteps.i_subtract_from(int,int)
        Then the result should be 5.0            # CalculatorSteps.the_result_should_be1(double)

    3 Scenarios (3 passed)
    9 Steps (9 passed)
    0m0,074s

在尝试了counter 和@DaveyDaveDave 代码后,输出如下所示: 开始的计数器行的打印位置不正确,但至少似乎可以正确执行。但是我仍然想知道为什么在最后一个减去方案的情况下它不执行@Before@Given@After

Feature: Calculator
  I use Calculator instead of calculating myself
@Before Count is: 0
@Given Count is: 1
@After Count is: 2
@Before Count is: 3

  @smokeTest
  Scenario Outline: Add two numbers # src/test/java/cucumber/junit/maven/cucumber_jvm/maven/calculatorFeature.feature:19
    Given I have a calculator       # CalculatorSteps.i_have_a_calculator()
    When I add 2 and 3              # CalculatorSteps.i_add(int,int)
    Then the result should be 5     # CalculatorSteps.the_result_should_be(int)
@Given Count is: 4
@After Count is: 5
@Before Count is: 6

  @smokeTest
  Scenario Outline: Add two numbers # src/test/java/cucumber/junit/maven/cucumber_jvm/maven/calculatorFeature.feature:20
    Given I have a calculator       # CalculatorSteps.i_have_a_calculator()
    When I add 4 and 5              # CalculatorSteps.i_add(int,int)
    Then the result should be 9     # CalculatorSteps.the_result_should_be(int)
@After Count is: 7

  @regressionTest
  Scenario: Subtract one number from another # src/test/java/cucumber/junit/maven/cucumber_jvm/maven/calculatorFeature.feature:23
    #Given I have a calculator
    When I subtract 2.5 from 7.5             # CalculatorSteps.i_subtract_from(int,int)
    Then the result should be 5.0            # CalculatorSteps.the_result_should_be1(double)

3 Scenarios (3 passed)
8 Steps (8 passed)
0m0,072s

【问题讨论】:

  • 您确定这些方法实际上是以错误的顺序执行的,还是仅仅是日志记录的顺序错误?我猜 Cucumber 输出来自一个适当的记录器,它可能正在做一些缓冲,并且仅在记录发生之后的某个时间点实际打印到控制台,您的 @Before@After 方法正在直接写入到标准输出,这将立即发生。
  • 不要认为你需要第二个@Given("^I have a calculatorr$")。尝试从步骤文件中删除它。
  • @DaveyDaveDave 好指针!我没有直接在我的钩子中使用 System.out.println,而是在主 Calculator 类中编写了方法。这避免了在开始时显示之前和之后两次,但在第三个场景(@regressionTest)之前和之后分别不执行之前和之后。但是在我的 Runner 类中,我已经指定了这两个标签。格式 = {"漂亮", "html:target/cucumber"}, 标签 = {"@smokeTest,@regressionTest"}
  • @Daniel 你是对的。我不需要第二个@Given("^I have acalculator$")。我删除了它们,场景通过了,但问题中的主要问题仍然存在。
  • 我建议,只是为了帮助您确定发生了什么,将计数器添加到 CalculatorSteps 类 - private static int counter = 0;,然后在您的 @Before@After 和 @987654350 @ 方法,输出计数器的值并将其递增 - 类似于 System.out.println("In before/after/given - " + counter++);。这样,根据数字的变化,您将能够确定代码是否以正确的顺序执行,而不管它是如何输出到控制台的。我想你会看到类似这样的输出:“In before 0”...“In given 1”...“In after 2”...等等。

标签: java junit automated-tests cucumber hook


【解决方案1】:

我认为功能正在按照您期望的顺序执行,这只是输出出现方式和时间的问题。

我刚刚复制并粘贴了您的源代码,并添加了一个 counter 变量,当我运行它时,我看到以下输出:

Setup Performed... 0
In given...1
...CleanUp Performed... 2
Setup Performed... 3
In given...4
...CleanUp Performed... 5
Setup Performed... 6
In given...7
...CleanUp Performed... 8

换句话说,数字表明这些事情的顺序正在按照您的预期发生。

如果它有助于说服您,我创建了以下RequiresSetupCalculator,如果在执行操作之前尚未设置它,并且如果我们尝试在之前未调用 @987654324 的情况下运行设置,则会引发异常@。

public class RequiresSetupCalculator {
  private static RequiresSetupCalculator instance;

  private int result = 0;
  private double result1 = 0;

  private boolean isSetup;

  private RequiresSetupCalculator() {
  }

  public static synchronized RequiresSetupCalculator setup() {
    if (instance == null) {
        instance = new RequiresSetupCalculator();
    }

    if (instance.isSetup) {
        throw new RuntimeException("I have already been set up");
    }

    instance.isSetup = true;

    return instance;
  }

  public void cleanUp() {
    if (!isSetup) {
        throw new RuntimeException("I wasn't set up in the first place");
    }

    isSetup = false;
  }

  public void add(final int arg1,
                final int arg2) {
    if (!isSetup) {
        throw new RuntimeException("I haven't been set up, no calculating for you!");
    }

    result = arg1 + arg2;
  }

  public int getResult() {
    if (!isSetup) {
        throw new RuntimeException("I haven't been set up, no calculating for you!");
    }

    return result;
  }

  public void subtract(final int arg1,
                     final int arg2) {
    if (!isSetup) {
        throw new RuntimeException("I haven't been set up, no calculating for you!");
    }

    result1 = arg2 - arg1;
  }

  public double getresult1() {
    if (!isSetup) {
        throw new RuntimeException("I haven't been set up, no calculating for you!");
    }

    return result1;
  }
}

要测试这一点,如果您将上述内容复制到一个新类中,以及现有的 Calculator,然后修改您的 CalculatorSteps 以使用 RequiresSetupCalculator 并调用 setupcleanUp 方法@Before@After 的测试方法如下:

public class CalculatorSteps {
  private RequiresSetupCalculator calculator;

  @Before
  public void setUp() {
    calculator = RequiresSetupCalculator.setup();
    System.out.println("Setup Performed...");
  }

  ... (existing test steps unchanged)...

  @After
  public void cleanUp() {
    System.out.println("CleanUp Performed...");
    calculator.cleanUp();
  }
}

现在,当您运行测试时,如果它仍然通过,我想我们可以确定 @Before 方法在每次测试之前运行一次且仅一次,并且@After 方法在每次测试之后运行,也只有一次。

对我来说,这是成功的。如果你在运行测试时抛出异常,那么就会发生一些奇怪的事情,但我相当有信心你会得到和我一样的结果。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-04-30
    • 1970-01-01
    相关资源
    最近更新 更多