2011-06-14 3 views
0

나는 SpecFlow를 배우고 있으며 간단한 Com-Sci 표준 FizzBuzz 프로젝트를 수행하고 있습니다. 주어진 숫자 범위 3로 나누기를 Fizz로 바꾸기 5로 나누기를 버즈로 바꾸기 3과 5로 나누기를 FizzBuzz로 바꿉니다.다중 의존 요구 사항에 대한 SpecFlow의 기능을 만드는 방법

이것은 매우 간단한 응용 프로그램이지만 나에게 질문을 제기했습니다. API에 대한 하나의 메소드 호출에서 모두 해고되는 여러 requiremts를 테스트하는 기능을 작성하는 방법은 무엇입니까? 예.

Feature: FizzBuzz 
    In order to display Fizz Buzz in  range of numbers 
    As a user I want to be able to see Fizz Buzz replace certain numbers 

Scenario: Replace muliples of three and five with Fizz, Buzz or FizzBuzz 
    Given I have a range of numbers from 1 to 15 
    When I press Submit 
    Then the result should be 
    | Numbers | 
    | 1 | 
    | 2 | 
    | Fizz | 
    | 4 | 
    | Buzz | 
    | Fizz | 
    | 7 | 
    | 8  | 
    | Fizz | 
    | Buzz | 
    | 11  | 
    | Fizz | 
    | 13  | 
    | 14 | 
    | FizzBuzz| 

또 다른 질문은 내가 할 경우이 기능이 더욱 의미있게하는 방법이다 바꾸기 방법 코드 FizzBuzz.Replace(1, 100); 다음과 같이 다음과 같이 API 호출

public static string Replace (int min, int max) 
{ 
     if (IsDiv3 && IsDiv5) {...} 
     if (IsDiv3) {...} 
     if (IsDiv5) {...} 
     ... 
} 

SpecFlow 나의 기능입니다 것 하나의 기능으로 모든 요구 사항을 집중해야합니다.

편집 두 번째 시나리오를 만들 자마자 첫 번째 시나리오가 실패하기 때문에 여러 시나리오를 만드는 데 어려움을 겪고 있습니다.

scenario 1: replace divisable by 3 with Fizz 
Expected = 1 2 Fizz 4 5 Fizz 7 8 Fizz 10 11 Fizz 13 14 Fizz 
Actual = 1 2 Fizz 4 5 Fizz 7 8 Fizz 10 11 Fizz 13 14 Fizz (First test) 
Actual = 1 2 Fizz 4 Buzz Fizz 7 8 Fizz Buzz 11 Fizz 13 14 Fizz (Second test) 

는 두 번째 시나리오는 첫 번째는 현재 실패에 불과 통과

Scenario 2: replace divisable by 5 with Buzz 
Expected = 1 2 Fizz 4 Buzz Fizz 7 8 Fizz Buzz 11 Fizz 13 14 Fizz 
Actual = 1 2 Fizz 4 Buzz Fizz 7 8 Fizz Buzz 11 Fizz 13 14 Fizz (Second test) 

다음 시나리오을 수행하십시오. 나는 시나리오 1, 2, 3을 할 수있는 API를 여는 것이 앱의 좋은 디자인이 될 것이라고 생각하지 않는다.

감사합니다,

+0

내가 다른 사람이 어떻게 이것을 테스트하는 좋은 콘크리트 힌트를 제공 생각합니다. 제 생각에 도덕적 인면은 API 또는 사양에 대한 TDD를 예제로 사용하면 문제가되지 않는다는 것입니다. 실제로 "유효하지 않은"시나리오는 절대로 설명해서는 안됩니다. 시나리오 1은 기능 사양에 해당하지 않으므로 도움이되지 않습니다. 예, 단순한 경우와 다른 측면을 위해 노력해야하지만 시나리오는 사양에 따라 모두 유효해야합니다. 시스템이 진화함에 따라 사양 자체가 변경되는 경우 또 다른 질문입니다. 그런 다음 적절하게 시나리오를 업데이트해야합니다. –

답변

5

메일 링리스트에서 메시지를 보았습니다. 당신은 소다의 테스트를 분할 할 경우, 버즈와 FizzBuzz 당신은 (즉, 각 "만약") 구현의 각 지점에 대한 시나리오를 만들려면 사양을 변경할 수 있습니다 :

Scenario: Replace multiples of three with Fizz 
    Given I have a range of numbers from 1 to 4 
    When I press Submit 
    Then the result should be 
    | Numbers | 
    | 1  | 
    | 2  | 
    | Fizz  | 
    | 4  | 

Scenario: Replace multiples of five with Buzz 
    Given I have a range of numbers from 4 to 5 
    When I press Submit 
    Then the result should be 
    | Numbers | 
    | 4  | 
    | Buzz  | 

Scenario: Replace multiples of three and five with FizzBuzz 
    Given I have a range of numbers from 14 to 16 
    When I press Submit 
    Then the result should be 
    | Numbers | 
    | 14  | 
    | FizzBuzz | 
    | 16  | 

귀하의 예제의 또 다른 관찰은 당신의 기대는 표 (본질적으로 배열)로 표현되지만 결과는 문자열로 표현됩니다. 이 예제에서 SpecFlow를 사용하여 API 테스트를 수행 중이므로 스펙 또는 API를 변경하여 두 클래스를보다 밀접하게 정렬하려고합니다.

예를 들어, 다음 API 변경 사항을 고려하십시오. "public static string [] Replace (int min, int max)".귀하의 단계는 쓰기 쉬울 것 - 이런 식으로 뭔가 :

[Binding] 
public class FizzBuzzSteps 
{ 
    private int _min; 
    private int _max; 
    private string[] _results; 

    [Given(@"I have a range of numbers from (\d+) to (\d+)")] 
    public void GivenIHaveARangeOfNumbers(int min, int max) 
    { 
     _min = min; 
     _max = max; 
    } 

    [When(@"I press Submit")] 
    public void WhenIPressSubmit() 
    { 
     _results = FizzBuzz.Replace(_min, _max); 
    } 

    [Then(@"the result should be")] 
    public void ThenTheResultShouldBe(Table table) 
    { 
     for (var i = 0; i < table.RowCount; i++) 
     { 
      var expected = table.Rows[i]["Numbers"]; 
      var actual = _results[i]; 
      Assert.AreEqual(expected, actual); 
     } 
    } 
} 

HTH, 댄 Mork

+0

감사합니다. Dan, 많은 의미가 있습니다. 이제 실제 세계를 구현하는 방법을 알 수 있습니다. 개인 필드보다는 최소, 최대 및 결과를 유지하기 위해 ScenarioContext를 사용하지 않겠습니까? – skyfoot

+0

예 ScenarioContext를 사용하면 비공개 필드에 대한 좋은 아이디어가됩니다. 그러면 다른 클래스에 있던 단계 정의에서 액세스 할 수 있습니다. – MattStacey

+0

ScenarioContext를 사용하여 값을 저장하려는 경우에 동의합니다. 이렇게하면 나중에 단계 방법을 쉽게 리팩터링 할 수 있습니다 (즉, FizzBuzzSteps 클래스의 정의에 묶이지 않음). 그 중 하나의 문제는 ... 내가 사용하고있는 SpecFlow의 버전은 ScenarioContext.Get(키) 메서드의 형식 매개 변수 T에 개체가 (값 형식이 아님) 필요하므로 해당 경로를 선택하지 않았습니다. 그러나 최신 릴리스에서 수정되었을 수 있습니다. 기꺼이 도와주세요. 투표 해줘서 고마워. –

0

당신이 보여 사양을 실행하면, specflow는이 같은 방법을 만들 제안합니다 :

[Then(@"the result should be")] 
    public void ThenTheResultShouldBe(Table table) 

당신은 반복하고 같은 테이블에서 값을 검색 할 수 있습니다

[Then(@"the result should be")] 
    public void ThenTheResultShouldBe(Table table) 
    { 
     foreach (var row in table.Rows) 
     { 
      var numberValue = row["Numbers"]; // the name of the column specified 
     } 
    } 

테스트를 좀 더 의미있게 만드는 방법으로서 나는 개인적으로이 테스트를 여러 시나리오로 나눌 수 있다고 말합니다. 숫자를 3으로 나누고 숫자를 5로 나눈 숫자로 하나의 시나리오를 작성합니다.

+0

시나리오를 테스트하기위한 단계와 주장이 있지만 다른 시나리오를 추가하자마자 첫 번째 테스트가 실패합니다. 편집 된 질문 – skyfoot

관련 문제