2014-05-23 49 views
2

给定一个具有方法SplitList和Update的类。正在从SplitList调用更新。测试是否通过使用moq嘲笑另一种方法来调用方法

class BaseClass 
{ 
    public void SplitList(ref IList<Type> objList) 
    { 
     IList<Type> SplitA = objList.Where(c=>c.currency == "USD").ToList(); 
     IList<Type> SplitB = objList.Where(c=>c.currency == "GBR").ToList(); 

     if(SplitA.Count() > 0) 
     { 
      Update(ref SplitA); 
     } 

     if(SplitB.Count() > 0) 
     { 
      Update(ref SplitB); 
     } 
    } 
} 

我想测试的是当我调用SplitList方法时,调用Update的次数。 我的意思是如果两者都被调用,或者是一个,或者没有。 需要测试该方法的边界条件。

我已经如何进行,因为这是,

class TestClass 
{ 
    [TestMethod] 
    void TestSplitList() 
    { 
     Mock<BaseClass> mock = new Mock<BaseClass>(); 
     mock.Setup(m=>m.Update(ref List)).Verifiable(); 
     mock.Object.SplitList(ref List); 
     mock.Verify(m=>m.Update(ref List), Times.Exactly(1)); 
    } 
} 

此代码给我误差, 上模拟预期调用恰好1次,但0次:M => m.Update( .List)

任何人都可以请帮忙吗?

+0

显示我们的更新方法执行 –

+0

公共虚拟更新(IList的 updateList) { \t诠释计数= 0; \t foreach(更新列表中的类型objType) \t { \t \t objType.OrderNo = count ++; \t} \t return updateList; }就像这样。 – Anshul

回答

1

是你的SplitList方法virtual? (因为您发布的代码可能与代码库不同)。在这种情况下,Moq会覆盖它,并且您的Update将不会被调用。您可以让非虚,或有订货数量称呼它通过加入这一行:如果你选择了这个方案,要小心

mock.CallBase = true; 

所有方法将“CallBase”(如果没有期望覆盖成员) 。

更新: 您正在向Update方法SplitList实施中传递不同列表。参数是objList,然后创建不同的列表(SplitASplitB)并将其传递给Update方法。由于SplitA(或SplitB!=objList,测试失败。

您真的必须在这里使用 ref吗?如果你删除它,代码会更简单,并且测试会通过。 没有裁判的名单仍然会有所不同,对不起,我错过了。我想你可能需要改变你的逻辑以允许更好的测试。

+0

是SplitList方法是虚拟的。但我尝试添加CallBase。它仍然给出同样的错误。我认为,当我通过模拟对象调用实际方法时,它不会调用内部方法。 – Anshul

+0

@ user3667853是的,这就是我的意思是“Moq会覆盖它”。 CallBase会解决它,但你有一个不同的问题,请看我的更新。 – henginy

+0

我更新了基类代码。删除了ref实现并返回了列表。仍然面临同样的问题。现在,我认为我将列表作为普通变量传递,但是在SplitList方法中,它将分裂到2个差异列表中,并使用这些新列表调用更新方法。也许这就是为什么模拟调用无法捕获更新是否被调用。 – Anshul

0

用虚拟方法嘲笑一个类将允许你验证方法。您也可以使用CallBase同时调用实际方法(Update)。

假设下面的代码(假设你发布更新不包含ref参数,我已经移除斯普利特不必要REF):

public class Type 
{ 
    public string currency { get; set; } 
    public int OrderNo { get; set; } 
} 
public class BaseClass 
{ 
    // w.r.t ref, do you mean to reassign objList to the filtered lists? 
    public void SplitList(ref IList<Type> objList) 
    { 
     var SplitA = objList.Where(c => c.currency == "USD").ToList(); 
     var SplitB = objList.Where(c => c.currency == "GBR").ToList(); 

     if (SplitA.Count() > 0) 
     { 
      Update(SplitA); 
     } 

     if (SplitB.Count() > 0) 
     { 
      Update(SplitB); 
     } 
    } 

    public virtual IList<Type> Update(IList<Type> updateList) 
    { 
     int count = 0; 
     foreach (Type objType in updateList) 
     { 
      objType.OrderNo = count++; 
     } 
     return updateList; 
    } 
} 

这个单元测试表明,虚拟Update方法可以验证以及被调用。如果您选择而不是以使用CallBase,则需要调整单元测试,因为不会发生列表中元素的突变。

[Test] 
public void TestSplitList() 
{ 
    var mock = new Mock<BaseClass>(); 
    mock.CallBase = true; // This will ensure the actual Update also gets called 
    IList<Type> fakeTypes = new List<Type> 
         { 
          new Type {currency = "GBR"}, 
          new Type {currency = "GBR", OrderNo = 100}, 
          new Type {currency = "JPY", OrderNo = 55} 
         }; 

    mock.Object.SplitList(ref fakeTypes); 

    mock.Verify(m => m.Update(It.IsAny<IList<Type>>()), Times.Exactly(1)); 
    mock.Verify(m => m.Update(It.Is<IList<Type>>(x => x.Any(y => y.currency == "GBR") 
       && x.Count == 2)), Times.Exactly(1)); 
    mock.Verify(m => m.Update(It.Is<IList<Type>>(
     x => x.Any(y => y.currency == "JPY"))), Times.Never); 
    Assert.AreEqual(3, fakeTypes.Count, "List itself must not have changed"); 

    // These tests show the effect of the actual `Update` method 
    Assert.IsTrue(fakeTypes.Any(t => t.OrderNo == 0 && t.currency == "GBR"), 
     "GBR must be ordered"); 
    Assert.IsTrue(fakeTypes.Any(t => t.OrderNo == 1 && t.currency == "GBR"), 
     "GBR must be ordered"); 
    Assert.IsFalse(fakeTypes.Any(t => t.OrderNo == 100 && t.currency == "GBR"), 
     "GBR must be ordered"); 
    Assert.IsTrue(fakeTypes.Any(t => t.OrderNo == 55 && t.currency == "JPY"), 
     "JPY must not be ordered"); 
} 

注:在List参数使用的ref是在当前的代码实现不必要的。由于您直接变更列表中的对象,所有引用这些项目的集合都可以看到这些更改。此外,你并没有改变列表本身(只是其中的元素),所以你不需要使Update参数ref,也不要从Update返回它。

相关问题