2012-04-01 42 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您将主要漂亮,很多都写一个模拟查询提供商,这将是不容易。