簡體   English   中英

測試是否通過使用moq模擬另一個方法來調用方法

[英]test if a method is called by mocking another method using moq

給定一個具有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 => m.Update(.List)

任何人都可以幫忙嗎?

您的SplitList方法是virtual嗎? (因為您發布的代碼可能與代碼庫不同。)在這種情況下,Moq將覆蓋它,並且不會調用您的Update 您可以將其設置為非虛擬,或者讓Moq通過添加以下行來調用它:

mock.CallBase = true;

如果您選擇此方法,請注意所有方法都將“CallBase”(如果沒有期望覆蓋該成員)。

更新:您正在將另一個列表傳遞給SplitList實現中的Update方法。 參數是objList ,然后創建一個不同的列表( SplitASplitB )並將它們傳遞給Update方法。 由於SplitA (或SplitB!= objList ,測試失敗。

你真的必須在這里使用 ref嗎? 如果刪除它,代碼將更簡單,測試將通過。 沒有參考,列表仍然會有所不同,對不起,我錯過了。 我認為您可能需要更改邏輯以允許更好的測試..

使用虛方法模擬類將允許您驗證方法。 您還可以使用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");
}

注意:在當前代碼實現中不需要在List參數上使用ref 因為您直接改變列表中的對象,所以這些更改對於引用這些項的所有集合都是可見的。 此外,您不是要更改列表本身(只是其中的元素),因此您不需要生成Update param ref ,也不需要從Update返回它。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM