2011-11-02 39 views
1

這個問題更多關於在SpecFlow中共享值的一般性討論。請根據您在SpecFlow中的經驗提供您可能具有的建設性反饋。對ScenarioContext.Current有用的抽象?

我對這項技術相對較新,在尋找解決方案來共享步驟定義文件中的值時,我發現了ScenarioContext.Current.GetScenarioContext.Current.Set。這些非常方便,但正如我所看到的那樣,存在一些問題。

  1. 這種方法涉及到很多打字。
  2. 使用字符串索引插入和檢索值類型,因此需要使用字符串常量或枚舉來確保步驟定義之間的一致性。
  3. 假設您試圖檢索的值已被插入可能並不安全。

我想出了一個抽象概念,我認爲這樣做更容易一些,我想知道人們對它的看法。

問題:我的數值已設置?

我對此的解決方案是將ScenarioContext.Current包裝在單例訪問器類中。這個類的行爲類似於ScenarioContext.Current,除了在找不到值時拋出AssertInconclusiveException

private static ScenarioContextAccessor instance; 

    public static ScenarioContextAccessor Instance 
    { 
     get 
     { 
      if (instance == null) 
      { 
       instance = new ScenarioContextAccessor(); 
      } 

      return instance; 
     } 
    } 

    private ScenarioContextAccessor() { } 

    public T Retrieve<T>(string index) 
    { 
     try 
     { 
      T val = (T)ScenarioContext.Current[index]; 
      if (val == null) 
      { 
       throw new Exception(); 
      } 

      return val; 
     } 
     catch 
     { 
      throw new AssertInconclusiveException(index + " of type " + typeof(T).Name + " was not found in the current scenario context. Did you execute your steps out of order?"); 
     } 
    } 

    public T Retrieve<T>() 
    { 
     try 
     { 
      T val = ScenarioContext.Current.Get<T>(); 
      if (val == null) 
      { 
       throw new Exception(); 
      } 

      return val; 
     } 
     catch 
     { 
      throw new AssertInconclusiveException("No object of type " + typeof(T).Name+ " could be found in the current scenario context. Did you execute your steps out of order?"); 
     } 
    } 

    public void Set(string index, object value) 
    { 
     ScenarioContext.Current[index.ToLower(CultureInfo.InvariantCulture)] = value; 
    } 

    public void Set<T>(T value) 
    { 
     ScenarioContext.Current.Set<T>(value); 
    } 
} 

問題:這需要輸入太多!

我對此的解決方案是有任何步驟定義,要求這些值將它們定義爲由ScenarioContextAccessor備份的私有屬性。任何訪問值類型的屬性都使用字符串常量作爲索引。

private string FolderName 
    { 
     get 
     { 
      return ScenarioContextAccessor.Instance.Retrieve<string>(FolderingScenarioContextKey.FolderName); 
     } 
     set 
     { 
      ScenarioContextAccessor.Instance.Set(FolderingScenarioContextKey.FolderName, value); 
     } 
    } 

    private UserDocumentMetadata Metadata 
    { 
     get 
     { 
      return ScenarioContextAccessor.Instance.Retrieve<UserDocumentMetadata>(); 
     } 
     set 
     { 
      ScenarioContextAccessor.Instance.Set<UserDocumentMetadata>(value); 
     } 
    } 

因此,現在我可以像訪問簡單屬性一樣輕鬆訪問我的共享值。

請提供任何建設性您可能有的反饋。謝謝!

回答

0

至於第1部分,我不同意。 如果數據沒有正確設置,我覺得測試失敗會更加有用。

至於第2部分,我已經使用了這樣的模式,尤其是獲取被測試對象的實例,因爲它可以節省大量輸入&潛在錯誤。

如果你只需要一類的虛擬實例是一個懶惰的初始化方法,而不是你的第1部分解決方案的另一模式非常有用(視情況):

public static Mock<T> GetOrMockAndStore<T>() where T : class 
    { 
     Mock<T> output; 
     if (ScenarioContext.Current.TryGetValue(out output)) 
     { 
      return output; 
     } 
     else 
     { 
      output = new Mock<T>(); 
      ScenarioContext.Current.Set(output); 
     } 
     return card; 
    } 

我使用起訂量 - 非常有用的框架。