cucumber java從入門到精通(4)Scenario Outline及數據驅動


cucumber java從入門到精通(4)Scenario Outline及數據驅動

到目前為止,我們的TodoList類工作良好,不過離我們的預期——任務清單系統還是有不少差距,究其原因不過如下:

  • 我們的feature不太完畢,沒有測試任務清單的增刪改查完成等功能;
  • 我們輸入的數據太過單一,只測試了1種輸入輸出的情況;

下面我們將着手解決數據輸入太過單一的問題。我們將使用Scenario Outline技術。

什么是Scenario Outline

什么是Scenario Outline呢,我們不妨先去命令行里看一下,在命令行中輸入

java -cp "jars/*" cucumber.api.cli.Main --i18n zh-CN

這將得到cucumber關鍵字的翻譯:

| feature          | "功能"                   |
| background       | "背景"                   |
| scenario         | "場景", "劇本"             |
| scenario_outline | "場景大綱", "劇本大綱"         |
| examples         | "例子"                   |
| given            | "* ", "假如", "假設", "假定" |
| when             | "* ", "當"              |
| then             | "* ", "那么"             |
| and              | "* ", "而且", "並且", "同時" |
| but              | "* ", "但是"             |
| given (code)     | "假如", "假設", "假定"       |
| when (code)      | "當"                    |
| then (code)      | "那么"                   |
| and (code)       | "而且", "並且", "同時"       |
| but (code)       | "但是"                   |

我們可以看到scenario outline被翻譯成了場景大綱或者是劇本大綱。簡單來說,場景大綱可以理解為同一個場景同一部戲,內容都一樣,台詞也一樣,只是換了不同的演員來演。每個場景大綱定義了不同的演員列表,該場景的台詞是一樣,演員的動作也相同,只是每次換不同的演員去表演。所謂鐵打的營盤流水的兵。因此,場景大綱里定義了幾組演員,這個場景就要演幾次。

cucumber的場景大綱不是用來定義演員的,而是用來定義數據的。大綱里定義幾組數據,那么該場景就要跑幾次。

增加Example

現在我們給我們的feature增加1組測試數據:

#language: zh-CN

功能:任務管理

    場景大綱: 完成任務
        假設 我的任務清單里有<total>個任務
        當 我完成<finished>件任務之后
        那么 我還剩下<left>件未完成的任務
        
        例子:
        | total | finished | left |
        |   3   |    1     |   2  |
        |   5   |    1     |   4  |

運行一下

run

我們發現cucumber報錯了:

#language: zh-CN
功能: 任務管理

  場景大綱: 完成任務             # todo.feature:5
    假設我的任務清單里有<total>個任務
    當我完成<finished>件任務之后
    那么我還剩下<left>件未完成的任務

    例子:

  場景大綱: 完成任務       # todo.feature:12
    假設我的任務清單里有3個任務 # TodoStep.iHaveSomeTasks(int)
    當我完成1件任務之后     # TodoStep.iFinishSomeTasks(int)
    那么我還剩下2件未完成的任務 # TodoStep.iLeftSomeTasks(int)

  場景大綱: 完成任務       # todo.feature:13
    假設我的任務清單里有5個任務 # TodoStep.iHaveSomeTasks(int)
      java.lang.AssertionError: expected:<3> but was:<5>
        at org.junit.Assert.fail(Assert.java:88)
        at org.junit.Assert.failNotEquals(Assert.java:834)
        at org.junit.Assert.assertEquals(Assert.java:645)
        at org.junit.Assert.assertEquals(Assert.java:631)
        at step_definitions.TodoStep.iHaveSomeTasks(TodoStep.java:15)
        at ?.假設我的任務清單里有5個任務(todo.feature:6)

    當我完成1件任務之后     # TodoStep.iFinishSomeTasks(int)
    那么我還剩下4件未完成的任務 # TodoStep.iLeftSomeTasks(int)

Failed scenarios:
todo.feature:13 # 場景大綱: 完成任務

2 Scenarios (1 failed, 1 passed)
6 Steps (1 failed, 2 skipped, 3 passed)
0m0.166s

java.lang.AssertionError: expected:<3> but was:<5>
        at org.junit.Assert.fail(Assert.java:88)
        at org.junit.Assert.failNotEquals(Assert.java:834)
        at org.junit.Assert.assertEquals(Assert.java:645)
        at org.junit.Assert.assertEquals(Assert.java:631)
        at step_definitions.TodoStep.iHaveSomeTasks(TodoStep.java:15)
        at ?.假設我的任務清單里有5個任務(todo.feature:6)

看起來密密麻麻,實際上的意思就是場景大綱里的第二組數據報錯了,我們的TodoList的實現無法滿足第二組數據,想想這也是應該的。

在這里要解釋一下例子這個關鍵字。例子在英文里叫Example,是feature關鍵字。緊跟在例子后的一半都是1個數據列表,從上文可以看到,一目了然。數據列表有表頭,表后下面的行跟着的是測試數據。

Scenario Outline運行流程

Scenario Outline的運行流程就是先從例子里讀一行數據,然后根據該數據的column也即是表頭,在steps里找到相應的<column>字段,用具體的數據進行替換。例子里有2行數據這個Scenario就會運行2次。因此我們上面的feature文件實際上是這樣運行的:

假設 我的任務清單里有3個任務
當 我完成1件任務之后
那么 我還剩下2件未完成的任務

假設 我的任務清單里有5個任務
當 我完成1件任務之后
那么 我還剩下4件未完成的任務
        

重構並讓用例通過

我們的用例已經測試出TodoList類的缺陷了,是時候重構一下了,先重構TodoStep.java文件

// TodoStep.java
package step_definitions;

import cucumber.api.java.zh_cn.*;
import cucumber.api.PendingException;
import static org.junit.Assert.*;
import implementation.TodoList;

public class TodoStep {              
    TodoList todo;
    
    @假設("^我的任務清單里有(\\d+)個任務$")                                                   
    public void iHaveSomeTasks(int totalTasks) throws Throwable {                        
        // Write code here that turns the phrase above into concrete actions     
        todo = new TodoList();
        todo.setTotalTaskCount(totalTasks);
    }                                                                            
                                                                                 
    @當("^我完成(\\d+)件任務之后$")                                                       
    public void iFinishSomeTasks(int finishedTasks) throws Throwable {                           
        // Write code here that turns the phrase above into concrete actions     
        todo.finishTask(finishedTasks);                                            
    }                                                                            
                                                                                 
    @那么("^我還剩下(\\d+)件未完成的任務$")                                                   
    public void iLeftSomeTasks(int leftTasks) throws Throwable {                        
        // Write code here that turns the phrase above into concrete actions        
        assertEquals(todo.getRestTasksCount(), leftTasks);                                            
    }                                                                            
}                                                           

我們這里假設TodoList有1個setTotalTaskCount方法,該方法用來設置當前TodoList中task的總數。另外我們還把假設中的斷言給去掉了,這是因為如果假設中有斷言,那就意味着你連前置條件都不信任,既然前提條件都不能保證,那么下面的步驟就沒有太多意義了,所以去掉會讓步驟定義更加的符合邏輯。

再重構TodoList.java文件

package implementation;

public class TodoList {
    int totalTaskCount;
    int finishedTaskCount;
    
    public TodoList() {
        totalTaskCount = finishedTaskCount = 0;
    }
    
    public int getTotalTaskCount() {
        return totalTaskCount;
    }
    
    public void setTotalTaskCount(int count) {
        totalTaskCount = count;
    }
    
    public void finishTask(int count) {
        finishedTaskCount = count;
    }
    
    public int getRestTasksCount() {
        return totalTaskCount - finishedTaskCount;
    }
}

代碼很簡單,就不一一解釋了。

運行一下

compile && run

結果如下,所有的step都pass了。

#language: zh-CN                                                          
功能: 任務管理                                                                  
                                                                          
  場景大綱: 完成任務             # todo.feature:5                                 
    假設我的任務清單里有<total>個任務                                                  
    當我完成<finished>件任務之后                                                   
    那么我還剩下<left>件未完成的任務                                                   
                                                                          
    例子:                                                                   
                                                                          
  場景大綱: 完成任務       # todo.feature:12                                      
    假設我的任務清單里有3個任務 # TodoStep.iHaveSomeTasks(int)                         
    當我完成1件任務之后     # TodoStep.iFinishSomeTasks(int)                       
    那么我還剩下2件未完成的任務 # TodoStep.iLeftSomeTasks(int)                         
                                                                          
  場景大綱: 完成任務       # todo.feature:13                                      
    假設我的任務清單里有5個任務 # TodoStep.iHaveSomeTasks(int)                         
    當我完成1件任務之后     # TodoStep.iFinishSomeTasks(int)                       
    那么我還剩下4件未完成的任務 # TodoStep.iLeftSomeTasks(int)                         
                                                                          
2 Scenarios (2 passed)                                                    
6 Steps (6 passed)                                                        
0m0.133s                                                                  

總結

從上面的例子里我們就可以看出自動化對生產力的提升幫助巨大。假設我們還需要測試100組數據,如果人肉手點的話,那么執行用例的人自然是痛不欲生,而且我們也沒有辦法完全保證數據輸入的准確性,畢竟老虎也會有打盹的時候,何況是人。但是如果用自動化測試的話,增加數據無非就是在數據表中增加一些行,工作量不是特別大,而且可以比較容易的檢查出數據是否准確。

像這種以增加輸入輸出數據的方式增加用例的測試用例設計方法,我們可以稱之為數據驅動。

下一節我們將進一步的實現項目工程學上的自動化,我們將使用maven來搭建cucumber項目。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM