2012-04-01 43 views
2

我遇到了麻煩PEX自動覆蓋方法調用LINQ的擴展方法,如其中(),包含()在本例中輸入:如何獲得PEX自動生成代碼涉及LINQ

public class MyEntity 
{ 
    public int Id { get; set; } 
} 

public interface IWithQueryable 
{ 
    IQueryable<MyEntity> QueryableSet(); 
} 

public class ConsumerOfIhaveIQueryable 
{ 
    private readonly IWithQueryable _withIQueryable; 
    public ConsumerOfIhaveIQueryable(IWithQueryable withIQueryable) 
    { 
     // <pex> 
     Contract.Requires<ArgumentNullException>(
      withIQueryable != null, "withIQueryable"); 
     // </pex> 
     _withIQueryable = withIQueryable; 
    } 

    public IEnumerable<MyEntity> GetEntitiesByIds(IEnumerable<int> ids) 
    { 
     Contract.Requires<ArgumentNullException>(ids != null, "ids"); 
     // <pex> 
     Contract.Assert 
      (this._withIQueryable.QueryableSet() != (IQueryable<MyEntity>)null); 
     // </pex> 
     IEnumerable<MyEntity> entities = 
     _withIQueryable.QueryableSet().Where(
      entity => ids.Contains(entity.Id)); 
     if (entities.Count() != ids.Count()) 
     { 
      return null; 
     } 
     return entities; 
    } 
} 

[PexClass(typeof(ConsumerOfIhaveIQueryable))] 
[PexAllowedExceptionFromTypeUnderTest(typeof(InvalidOperationException))] 
[PexAllowedExceptionFromTypeUnderTest(typeof(ArgumentException), AcceptExceptionSubtypes = true)] 
[TestClass] 
public partial class ConsumerOfIhaveIQueryableTest 
{ 
    [PexMethod] 
    public IEnumerable<MyEntity> GetEntitiesByIds(
     [PexAssumeUnderTest]ConsumerOfIhaveIQueryable target, 
     int[] ids) 
    { 
     var result = target.GetEntitiesByIds(ids); 
     PexAssert.IsTrue(result.Count() == ids.Length); 
     return result; 
    } 
} 

當我在這個PexMethod運行PEX探索我看到以下問題:

  • 我不斷收到同樣的異常和PEX建議保持在Contract.Assert的形式相同的「不變」的修復程序你在//區域看到: 我相信問題是某種程度上與Pex如何與Linq相關,但我不確定

---說明 失敗測試:ArgumentNullException,值不能爲空。 參數名:源

[TestMethod] 
[PexGeneratedBy(typeof(ConsumerOfIhaveIQueryableTest))] 
[PexRaisedException(typeof(ArgumentNullException))] 
public void GetEntitiesByIdsThrowsArgumentNullException385() 
{ 
    using (PexChooseBehavedBehavior.Setup()) 
    { 
     SIWithQueryable sIWithQueryable; 
     ConsumerOfIhaveIQueryable consumerOfIhaveIQueryable; 
     IEnumerable<MyEntity> iEnumerable; 
     sIWithQueryable = new SIWithQueryable(); 
     consumerOfIhaveIQueryable = 
     ConsumerOfIhaveIQueryableFactory.Create((IWithQueryable)sIWithQueryable); 
     int[] ints = new int[0]; 
     iEnumerable = this.GetEntitiesByIds(consumerOfIhaveIQueryable, ints); 
    } 
} 

---異常詳細

System.ArgumentNullException:值不能爲空。 (System.Linq.IQueryable'1 source,System.Linq.Expressions.Expression'1> predicate) c:\ users \ moran \ (System.Collections.Generic.IEnumerable'1 PexIQueryable.ConsumerOfIhaveIQueryable.GetEntitiesByIds(System.Collections.Generic.IEnumerable`1 ids) c(文件\ visual studio 2010 \ Projects \ PexTuts \ :\ users \ moran \ documents \ visual studio 2010 \ Projects \ PexTuts \ PexIQueryable \ PexIQueryable.Tests \ ConsumerOfIhaveIQueryableTest.cs(34):at System.Collections.Generic.IEnumerable'1 PexIQueryable.ConsumerOfIhaveIQueryableTest.GetEntitiesByIds(PexIQueryable.ConsumerOfIhaveIQueryable target, System.Int32 [] ids)

  • 我無法讓PEX生成相關輸入。正如你所看到的,我試圖通過在我的代碼中添加一個PexAssert和一個分支來「幫助」它,但是這個分支永遠不會被覆蓋,即使應該是應該相對簡單一些來生成一個可以走這條路徑的代碼。 PEX只會嘗試傳遞null或一個空數組作爲Ids列表(我在某處讀到PEX更容易處理數組(int [])而不是IEnumerable)

很想得到一些意見這個...

順便說一句,這是我第一次SO後,希望我沒有垃圾郵件太多的代碼和信息。

莫蘭

+0

我剛剛注意到,當你張貼了這個...我已經過?不過,這是一個有趣的調查! – nicodemus13 2012-04-10 20:11:31

回答

1

一段時間建立的代碼之後,我做了一些假設,假設你通過Moles存根存根IWithQueryable,並且NullArgume當您刪除Contract斷言QueryableSet()方法不返回null時,會發生ntException。

至於代碼,IMO越多代碼越好,只要它是相關的 - 要好得多,而不是太少,所以沒關係。如上所述,儘量弄清楚代碼中的所有假設(例如摩爾斯樁(因爲有不同的方法來實現這一點,這是人們必須假定的)

我不是100%再問。該代碼失敗,因爲存根IWithQueryable object沒有爲QueryableSet()方法的implmementation和方法返回nullPexAssert這裏不會幫助它找出如何創建一個LINQ提供程序,這正是你要求它做的。該PexChooseBehavedBehavior.Setup()只是替換上的痣存根(不具有自定義委託),通過該default(T)默認行爲代表任何電話,所以這就是爲什麼source是空值的QueryableSet()被初始化爲null

你可以(在提供創建QueryableSet()方法的一種方式的意義至少)的幾種方法解決這個問題。您可以創建一個工廠方法來生成或者整個SIWithQueryable,或只是QueryableSet委託。這是Pex建議的(但是,對我來說,它使類型和命名空間混亂起來)。例如:

/// <summary>A factory for Microsoft.Moles.Framework.MolesDelegates+Func`1[System.Linq.IQueryable`1[StackOverflow.Q9968801.MyEntity]] instances</summary> 
public static partial class MolesDelegatesFactory 
{ 
    /// <summary>A factory for Microsoft.Moles.Framework.MolesDelegates+Func`1[System.Linq.IQueryable`1[StackOverflow.Q9968801.MyEntity]] instances</summary> 
    [PexFactoryMethod(typeof(MolesDelegates.Func<IQueryable<MyEntity>>))] 
    public static MolesDelegates.Func<IQueryable<MyEntity>> CreateFunc() 
    { 
     throw new InvalidOperationException(); 

     // TODO: Edit factory method of Func`1<IQueryable`1<MyEntity>> 
     // This method should be able to configure the object in all possible ways. 
     // Add as many parameters as needed, 
     // and assign their values to each field by using the API. 
    } 

    /// <summary>A factory for Microsoft.Moles.Framework.MolesDelegates+Func`1[System.Linq.IQueryable`1[StackOverflow.Q9968801.MyEntity]] instances</summary> 
    [PexFactoryMethod(typeof(SIWithQueryable))] 
    public static SIWithQueryable Create() 
    { 
     var siWithQueryable = new SIWithQueryable(); 
     siWithQueryable.QueryableSet =() => { throw new InvalidOperationException(); }; 

     return siWithQueryable; 
     // TODO: Edit factory method of Func`1<IQueryable`1<MyEntity>> 
     // This method should be able to configure the object in all possible ways. 
     // Add as many parameters as needed, 
     // and assign their values to each field by using the API. 
    } 
} 

,然後用兩行分配sIWithQueryable之一把它掛到測試方法:

[TestMethod] 
[PexGeneratedBy(typeof(ConsumerOfIhaveIQueryableTest))] 
public void GetEntitiesByIdsThrowsArgumentNullException678() 
{ 
    SIWithQueryable sIWithQueryable; 

    // Either this for the whole object. 
    sIWithQueryable = MolesDelegatesFactory.Create(); 

    // Or this for just that delegate. 
    sIWithQueryable = new SIWithQueryable(); 
    sIWithQueryable.QueryableSet = MolesDelegatesFactory.CreateFunc(); 

    ConsumerOfIhaveIQueryable consumerOfIhaveIQueryable; 
    IEnumerable<MyEntity> iEnumerable; 
    consumerOfIhaveIQueryable = ConsumerOfIhaveIQueryableFactory.Create((IWithQueryable) sIWithQueryable); 
    int[] ints = new int[0]; 
    iEnumerable = this.GetEntitiesByIds(consumerOfIhaveIQueryable, ints); 
} 

那麼這將調用你的工廠方法IWithQueryable創建存根時。這仍然是一個問題,因爲重新開始探索會消除存根設置。

如果您提供無參數工廠方法來創建存根(MolesDelegatesFactory.CreateFunc()),那麼Pex將知道這一點並生成測試以使用它。因此,它將正確管理跨測試再生的行爲。 Unfortuantely,PEX建議創建此委託然而,作爲工廠方法 - ,它不會被調用,默認的實現總是使用,似乎一個人嘲笑父類型。

但是,我想知道爲什麼你要創建一個簡單的界面IWithQueryable換行,以及你期望如何處理IQueryable。爲了做什麼是非常有用的,你就會有大量的工作正在進行,以應對IQueryable界面 - ProviderExpression您將主要漂亮,很多都寫一個模擬查詢提供商,這將是不容易。