簡體   English   中英

如何使用Moq模擬接口的`object.Equals(object obj)`

[英]How to mock `object.Equals(object obj)` for an interface using Moq

我有一個有趣的問題包圍你的頭。 考慮一下這樣的界面:

public interface IMyThing
{
    int Id { get; }
}

現在我想測試使用此接口的代碼。 也許有一些LINQ魔術。 像這樣的東西:

public class SomeClass
{
    private IMyThing _thing;

    ...

    public bool HasThing(IEnumerable<IMyThing> things)
    {
        return things.Contains(_thing);
    }
}

我正在使用Moq IMyThing實現IMyThing所有對象:

public static IMyThing MockMyThing(int newId)
{
    var mock = new Mock<IMyThing>();
    mock.Setup(s => s.Id).Returns(newId);
    mock.Setup(s => s.Equals(It.IsAny<object>())).Returns<object>(obj =>
    {
        if (typeof(IMyThing).IsAssignableFrom(obj.GetType()))
        {
            return ((IMyThing)obj).Id == newId;
        }

        return false;
    });

    return mock.Object;
}

這就是事情。 上面的代碼編譯沒有警告,但永遠不會工作。 MoqEquals()方法創建了一個攔截器,但它永遠不會到達。 而是調用對象代理的equals方法。 我譴責的事實是我在嘲笑一個界面而不是一個具體的類。

更新:剛剛意識到Moq甚至沒有創建攔截器。

當然,我可以像這樣擴充IMyThing界面:

public interface IMyThing : IEquatable<IMyThing>
{
    int Id { get; }
}

LINQ運算符將識別IEquatable<T>接口並使用它。

我不想這樣做是因為:

  • 這僅適用於其他IMyThing對象
  • IEquatable<T>不是為了這個目的
  • 我不想讓我的模型變得模糊不清

你怎么解決這個問題?

我最終為Github上的Moq項目貢獻代碼(參見問題#248 )。 通過這種更改,可以模擬object.GetHashCode() object.Equals(object obj)object.GetHashCode()object.GetHashCode() object.ToString() ,甚至可以模擬接口模擬。

讓我們看看它是否被接受。

我認為問題來自於Equals方法不在你嘲笑的界面上。 如果您使用可覆蓋的Equals方法創建一個類(即使它什么也不做),那么您可以模擬它。

public class MyTestThing : IMyThing
{
    public virtual int Id { get; }

    public override bool Equals(object obj)
    {
        return base.Equals(obj);
    }
}

[TestCase(55)]
public void Can_mock_equals_method(int newId)
{
    var mockThing = new Mock<MyTestThing>();

    mockThing.Setup(t => t.Id).Returns(newId);
    mockThing.Setup(t => t.Equals(It.IsAny<object>()))
        .Returns<object>(t => (t as IMyThing)?.Id == newId);

    Assert.That(mockThing.Object.Equals(new MyRealThing(newId)));
}

請注意,如果您在MyTestThingMyTestThing Equals方法, MyTestThing此測試將失敗,因為Moq無法再模擬它。

如果您要創建這樣的測試類,那么在類本身中實際完全實現Equals可能更有用,因此您不必費心使用Moq進行設置。 您甚至可以更進一步創建一個抽象基類,其中唯一實現的方法是Equals並在使用Moq的測試中使用它,並從中派生您的實際實現。

如果執行比較的方式可能會發生變化,則不應使用直接比較,而是使用可以為您進行比較的對象。

考慮對您的類進行更改,如下所示:

public class SomeClass
{
    private IMyThing _thing;

    public bool HasThing(IEnumerable<IMyThing> things, IEqualityComparer<IMyThing> comparer = null)
    {
        comparer = comparer ?? EqualityComparer<IMyThing>.Default;
        return things.Contains(_thing, comparer);
    }
}

然后你只需要模擬比較器。

也許我完全不理解你,但我沒有看到一個擴展或者覆蓋Equy Equals()函數的IMyThing 所以我想我的第一種方法將是overide或extandes功能,如果它不起作用我將IMyThing : IEquatable<IMyThing> ,我知道IEquatable<T>不是為了這個目的,但它關閉。 而最后我不認為你需要這樣做,但它存在,只需創建一個像bool IsEquals(IMyThing other){//check if equals}的函數

暫無
暫無

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

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