Moq Equals funcționează numai cu eșec

Folosesc cadrul Moq pentru teste unitare și am dat peste această problemă interesantă.

public interface Bar : IEquatable
{
}

[TestClass]
public class TestClass
{
    Mock a;
    Mock b;

    public TestClass()
    {
        a = new Mock();
        b = new Mock();

        a.Setup(bar => bar.Equals(b.Object)).Returns(true);
    }

    [TestMethod]
    public void AssertEqualsTest()
    {
        Assert.AreEqual(a.Object, b.Object); //fails
    }

    [TestMethod]
    public void AssertIsTrueTest()
    {
         Assert.IsTrue(a.Object.Equals(b.Object)); //passes
    }
}

Prima ediție

Deci, Assert.AreEqual doar eșuează. Nu vreau să folosesc linia din cel de-al doilea test de fiecare dată când trebuie să verific egalitatea, deși majoritatea (dacă nu toate) dintre clasele mele sunt moștenite de la IEquatable.

S-ar putea să credeți că nu reușește, deoarece Setup setează numai funcția IEquality.Equals() (care Assert.AreEqual probabil nu verifică), dar dacă adăugați linia

a.Setup(x => x.Equals((object)b.Object)).Returns(true);

la constructor, acesta încă nu reușește.

A doua ediție

If you comment out the : IEquatable from the interface declaration (so that a.Setup overwrites object.Equals), both tests fail.

Rezultatul dorit este să puteți seta egal pe un obiect Mock și să sunați Assert.AreEqual .

3
De ce doriți să comparați obiectele generate într-un mod Mock ?
adăugat autor JaredPar, sursa
Este pentru a testa un operator de egalitate pe o altă clasă. Funcția a rămas fără succes, așa că am intrat în ea și am observat că cei doi nu erau egali cum credeam că ar fi trebuit să fie.
adăugat autor hehewaffles, sursa
Pentru a pune întrebarea @ JaredPar într-un mod diferit, care este obiectul/unitatea testată?
adăugat autor manojlds, sursa

2 răspunsuri

Prima emisiune

Verificat prin dotPeek. Assert.AreEqual apelează metoda statică object.Equals pentru a compara instanțele. object.Equals utilizează mai întâi operator == și din moment ce exemplul fals nu implementează acel operator, acesta va implica implicit compararea referințelor. În mod evident, a și b sunt instanțe diferite, astfel încât comparația returnează false.

Al doilea număr

Nu m-am uitat la intervalele lui Moq, dar presupun că acest lucru se întâmplă deoarece interfața nu declară o metodă Equals. Confirmat cu următoarele (care reușește):

public interface IBar
{
}

public class Bar : IBar
{
    public override bool Equals(object obj)
    {
        return false;
    }
}

[TestClass]
public class Class1
{
    [TestMethod]
    public void TestMoq()
    {
        var a = new Mock();
        var b = new Mock();

        a.Setup(bar => bar.Equals(b.Object)).Returns(true);

        Assert.IsTrue(a.Object.Equals(b.Object));
    }
}

If I remove the Bar.Equals override, the test will also fail. Just a guess but since Moq uses Castle internally, this issue can be explained by this Q&A.

Oricum, cred că ceea ce faceți acum cu Assert.IsTrue (a.Object.Equals (b.Object)); și IEquatable este o soluție suficientă pentru acest lucru.

Apropo, așa cum a întrebat JaredPar de mai sus, de ce comparăți furie?

4
adăugat

Obisnuiam..

mockLine2.CallBase = True

Și de ce?

Testează un serviciu de comandă. La comandă există două linii, serviciul elimină orice linie care corespunde anumitor criterii. Linile sunt o listă, lista (etc) folosește .equals() pentru a găsi elementul pe care îl doriți, astfel încât să eliminați linia, aveți nevoie de o implementare de egal care trece:

Assert.IsTrue(mockLine2.Object.Equals(mockLine2.Object)

"Moq mock nu detectează că o linie este egală, astfel încât colecția de linii din ordin nu va reuși să găsească linia.")

S-ar putea argumenta că, deoarece Ordinul nu este clasa testată, ar trebui să batem ordinea și să afirmăm că order.Lines.Remove() este apelată cu linia dreaptă, dar am găsit-o în echilibru mai putin dureroasa de a folosi obiectele reale de domeniu (toate sunt destul de prost) decat sa le bat joc de ele.

2
adăugat