给定一个具有SplitList和Update方法的类。正在从SplitList调用更新。
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 =&gt; m.Update(的.List)
有人可以帮忙吗?
答案 0 :(得分:1)
您的SplitList
方法是virtual
吗? (因为您发布的代码可能与代码库不同。)在这种情况下,Moq会覆盖它,并且不会调用Update
。您可以将其设置为非虚拟,或让Moq通过添加以下行来调用它:
mock.CallBase = true;
如果您选择此方法,请注意所有方法将为“CallBase”(如果没有期望覆盖该成员)。
更新:
您在Update
实施中向SplitList
方法传递了不同的列表。参数为objList
,然后您创建了不同的列表(SplitA
和SplitB
)并将其传递给Update
方法。自SplitA
(或SplitB
)!=
objList
以来,测试失败。
你真的必须在这里使用列表仍然是不同的没有参考,抱歉,我错过了。我认为您可能需要更改逻辑以允许更好的测试.. ref
吗?如果你删除它,代码将更简单,测试将通过。
答案 1 :(得分:0)
使用虚方法模拟类将允许您验证方法。您也可以使用CallBase
同时调用实际方法(Update
)。
假设以下代码(假设您发布的更新不包含ref
参数,我已从Split中删除了不必要的引用):
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");
}
注意:在当前的代码实现中,不需要在ref
参数上使用List
。因为您直接改变列表中的对象,所以这些更改对于引用这些项的所有集合都是可见的。此外,您不会更改列表本身(只是其中的元素),因此您不需要制作Update
参数ref
,也不需要从{{ 1}}。