创建可配置的相关资源

时间:2016-09-06 18:51:41

标签: java cucumber cucumber-jvm

描述

目前,我正在为服务创建一些Cucumber功能。让我们说我有一个用于配置特斯拉汽车的服务:

public class TeslaCar {
    Engine engine;
    Color color;
    // other things here...
}

,其中

public class Engine {
    boolean isAllWheelDrive;

    // for 60, 70, 90D, P100D
    KilowattEnum kWh;

    // other things here...
}

简单的创建调用很容易实现,我只需使用GivenAdd结合配置资源,然后调用 create

因此对于CreateEngine,我会这样做:

Feature: CreateEngine
    Scenario Outline: Create Engine
        Given an engine was initialized
          And engine has <all_wheel>
          And kwh is <kwh>
        When engine is created
        Then engine creation succeeds

    Examples:
    | kwh | all_wheel |
    | 60  | false     |
    | 60  | true      |
    | 70  | false     |

现在我需要为DriveCar编写集成测试。我想用Given确保有一辆我可以驾驶的新车。我想创造一辆新车,因为我不知道过去的汽车状态是什么。如果电池电量为10%,那么它将不是一个好的测试。然后,由于集成测试取决于我的特斯拉类型,我想在我的功能文件中配置它。

所以它看起来像:

Feature: Drive Car
  Scenario: Test drive Tesla
    Given a car is initialized
      And engine kwh is P90D
      And engine is all wheel drive
      And engine is created
      # Need to call CreateEngine with above line, but is this clunky?
      And car is created
      # Need to call CreateCar above because Engine is a parameter to CreateCar
    When car is driven
    Then max speed is 120mph

问题

这一开始似乎很合理,但是有更好的方法吗?如果需要为DriveCar配置更多的东西,那么它会很快变得笨拙。

问题

  1. 这是测试的不良做法吗?
  2. 有没有更好的方法来实现这个目标?
  3. 我不是在想黄瓜的方式吗?
  4. 可能的解决方案1?

    我想到的一件事是使用@tags。这让我说,“每当我使用@60kwh&#39;时,我需要一台60kWh的引擎。但这并没有很好的延伸。

    可能的解决方案2?

    不要配置汽车,而只使用默认汽车。

3 个答案:

答案 0 :(得分:3)

我会像发动机一样压缩向汽车添加组件的步骤。使用DataTable添加引擎的所有属性。从这个新步骤定义中,只需要DataTable作为参数,您可以调用现有代码进行引擎设置。这样,每次添加新属性时都不需要添加新的步骤定义。只需附加到DataTable的末尾。

如果你有一个新的汽车组件,你需要在你的功能文件中加上3行加上一个步骤定义。例如,我在该功能中添加了一个变速箱。

如果在特征文件DataTable中,您将表头命名为与实例变量相同,那么如果您放置List<Engine> engine之类的参数而不是DataTable,Cucumber会自动将值放入类中。

我看到的问题是,如果您有一个具有多个设置的属性。例如,引擎模式可以是City,Cruise和Sport。也许你可以使用逗号分隔的字符串然后拆分它。

Feature: Drive Car
  Scenario: Test drive Tesla
    Given A car with following components

    And Add engine with specifications
      | kwh  | allwheel |
      | P90D | true     |

    And Add gearbox with specifications
      | noofgears  | auto |  
      | 4          | true |          

    And assemble car
    When car is driven
    Then max speed is 120mph

如果您想要更多乐趣,请考虑将其作为场景大纲并在一个功能中测试多个组合。但是接下来你会有一个很大的示例表行数据。我实际上会使用该路由,因为我会从一个场景中获得更多,它会将数据从步骤推送到示例表中。

功能文件中的步骤似乎总结了代码,而不是像步骤这样的行为 - 引擎已初始化。但是,如果每个人都理解它并为您的目的服务,那么为什么要改变它。

答案 1 :(得分:3)

Cucumber专为验收测试而设计,测试可以运行整个系统(因此它们也是集成测试),因为用户可以并且可以被利益相关者和开发人员理解。

您的CreateEngine方案不适用于整个系统,但对于只对开发人员有意义的软件组件,所以我不是用Cucumber测试它,而是使用单元测试框架

你的&#34;驾驶汽车&#34;另一方面,情景是一种适当的验收测试。不过,它有很多软件细节。我写的是这样的:

Feature: Drive Car

  Scenario: Test drive Tesla
    Given there is a car with an all-wheel-drive engine and P90D engine kwh
    When the car is driven
    Then the max speed is 120 mph

(我不确定&#34; P90D引擎kwh&#34;语法正确,所以请在必要时更正。)

重点:

  • 没有提及软件细节。
  • 没有提到对结果不重要的值;他们只是违约。请注意,如果有任何其他值对结果很重要,那么也应该提及它们,以便读者在其前面的所有信息都需要验证结果的正确性,而无需阅读步骤定义。例如,如果特斯拉也有尾鳍和尾鳍尺寸影响最大速度,那么定义汽车的步骤还应该提到&#34;大尾鳍&#34;或者其他什么。

我不确定您是否需要比我展示的更灵活的汽车定义步骤。我通常发现在大多数情况下只需要几个简单的步骤。尽量保持简单,只有在需要时才能构建更复杂的步骤。

此外,抵制为所有数据组合编写Cucumber场景(或场景轮廓)的冲动。验收测试很慢并且需要维护,因此您希望尽可能少地接受测试,同时仍然向利益相关者公开所有重要的要求。当您开始编写组合Cucumber场景时,请考虑是否可以将一个Cucumber场景作为示例编写,并在单元测试中测试所有组合。

答案 2 :(得分:2)

非常好的问题,Dave Schweisguth也有一个很好的答案,我也会补充一下。

如果您的汽车结构具有所有配置选项,并且您希望编写集成测试来处理不同类型的汽车,则可以通过命名汽车来消除在功能中指定每项维护的详细信息的需要。例如,我可能有:

  • 拉力赛车:4轮驱动,6档,超轻量机箱, 滚动条
  • 出租车:2轮驱动,4档,防污内饰
  • 中年危机车:4轮驱动,轿跑车,吊顶,皮革内饰......

然后你会写下这样的功能:

Given I have a rally car
...

Given I have a taxi

等。等

现在重要的是,在你们这个时候,你们不会诉诸于回到细节,例如

Given I have a taxi
Then I should have 2 wheel drive
And I should have 4 gears

是糟糕的,因为你混合了两个抽象层次,详细的抽象层次和更高层次的抽象层次。相反,你应该为出租车编写出租车场景

e.g。

Given I have a taxi
When my passengers puke over my interior
Then it should be easy to clean

这意味着您的名字必须对您的利益相关者很重要。

您从这种方法中获得的一件事是在更改规格时降低变更成本。例如,如果我们确定出租车应该是4wd,我们不必改变每个场景,我们只需改变步骤def`鉴于我有一辆出租车'。

我将按以下步骤实施步骤

Given 'I have a taxi' do
  create_taxi
end

module TaxiStepHelper
  def create_taxi
    create_car(
      engine: 
      drive: 
      ...
     )
   end

我认为这种方法是“使用更高级别的抽象”。但Matt Wynne提出了一个很好的方式来描述它“推动下来”。我们正在做的是推动汽车配置如何从场景到步骤定义助手的配置。