首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >创建可配置的依赖资源

创建可配置的依赖资源
EN

Stack Overflow用户
提问于 2016-09-06 18:51:40
回答 3查看 92关注 0票数 2

描述

目前,我正在为服务创建一些黄瓜特性。假设我有一个用于配置Tesla汽车的服务:

代码语言:javascript
复制
public class TeslaCar {
    Engine engine;
    Color color;
    // other things here...
}

哪里

代码语言:javascript
复制
public class Engine {
    boolean isAllWheelDrive;

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

    // other things here...
}

简单的create调用很容易实现,我只是使用GivenAdd相结合来配置资源,然后调用create。

所以对于CreateEngine,我会这样做:

代码语言:javascript
复制
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%,这将不是一个好的测试。然后,由于集成测试取决于我所拥有的Tesla的类型,所以我想在我的特性文件中配置它。

所以看起来是:

代码语言:javascript
复制
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. 我不是在想黄瓜的方法吗?

可能的解决方案1?

我想到的一件事是使用@tags。这将让我说,‘我需要一个60千瓦的引擎,每当我使用@60kwh’。但这并不是很好的延伸。

可能的解决方案2?

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

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2016-09-06 20:59:13

黄瓜是为验收测试而设计的,这些测试使用整个系统(因此它们也是集成测试),因为用户将并且可以被涉众以及开发人员理解。

您的CreateEngine场景不是针对整个系统的,而是针对一个只对开发人员有意义的软件组件的,所以我不会用Cucumber,而是用一个单元测试框架来测试它。

另一方面,您的“驾驶汽车”方案是一个适当的验收测试。不过,它有很多软件细节。我会写成这样:

代码语言:javascript
复制
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

(我不确定"P90D engine kwh“是否正确语法,因此请根据需要进行更正。)

要点:

  • 没有提到软件的细节。
  • 没有提到对结果不重要的值;它们只是默认值。请注意,如果有其他对结果很重要的值,也应该提到它们,这样读者就可以在前面得到所有需要的信息来验证结果的正确性,而不必读取步骤定义。例如,如果特斯拉也有尾鳍和尾鳍尺寸影响最大速度,定义汽车的步骤也应该提到“大尾翼”或其他任何东西。

我不确定你是否需要比我展示的更灵活的汽车定义步骤。我通常发现,在大多数情况下只需要几个简单的步骤。一开始试着保持简单,只有当你需要的时候才构建更复杂的步骤。

此外,不要急于为所有数据组合编写Cucumber场景(或场景大纲)。验收测试速度慢,需要维护,因此您希望在向涉众公开所有重要需求的同时尽可能少使用这些测试。当您开始编写组合Cucumber场景时,请考虑是否可以编写一个Cucumber场景作为示例,并测试单元测试中的所有组合。

票数 3
EN

Stack Overflow用户

发布于 2016-09-06 20:44:12

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

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

如果在特性文件DataTable中,您将表头命名为实例变量,那么如果您将参数设置为List<Engine> engine而不是DataTable,Cucumber将自动将这些值放入类中。

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

代码语言:javascript
复制
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

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

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

票数 3
EN

Stack Overflow用户

发布于 2016-09-07 09:40:41

非常好的问题,戴夫·施魏斯古斯给出了一个很好的答案,我也会补充一下。

当您有一个像您的汽车这样的结构及其所有配置选项,并且您希望编写集成测试来处理不同类型的汽车时,您可以通过命名这些汽车来消除在您的特性中指定每个注意事项的细节的需要。例如,我可能有:

  • 拉力车:4轮驱动,6齿轮,超轻底盘,滚轴。
  • 出租车:2轮驱动,4个齿轮,耐沾污内部。
  • 中年危机车:4轮驱动,跑车,坠顶,皮革内饰.

然后,您将编写如下功能:

代码语言:javascript
复制
Given I have a rally car
...

Given I have a taxi

等等

现在,重要的是,在你的时候,你不要求助于回到细节,例如

代码语言:javascript
复制
Given I have a taxi
Then I should have 2 wheel drive
And I should have 4 gears

这是不好的,因为你混合了两个抽象层次,一个是详细的,另一个是高级的。相反,您应该为出租车编写出租车场景

例如:

代码语言:javascript
复制
Given I have a taxi
When my passengers puke over my interior
Then it should be easy to clean

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

您从这种方法中得到的一件事是,当您更改规范时,可以降低更改的成本。例如,如果我们决定出租车应该是4wd,我们不需要改变每个场景,我们只需更改步骤def‘如果我有一辆出租车’。

我将按以下方式实现步骤防御

代码语言:javascript
复制
Given 'I have a taxi' do
  create_taxi
end

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

我认为这种方法是“使用更高层次的抽象”。但是马特·韦恩想出了一种很好的方式来描述它,那就是“如何往下推”。我们正在做的是通过步骤定义将如何配置car的责任推给步骤定义助手。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/39355957

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档