2017-05-19 2 views
1

Ich habe einen Manager (Business-Schicht), die ein Repository (Datenzugriffsebene mit EF) aufruft. Die Logik des Managers wird zweimal eine Methode des Repository mit zwei verschiedenen Lambda-Ausdrücken als Parameter aufrufen.Wie verspotten Sie eine Methode zweimal mit unterschiedlichen Lambda-Ausdruck?

Meine Frage ist, wie man mein Repository spotten kann, um eine gegebene Antwort für ein erstes Lambda zurückzugeben, aber eine andere Antwort für ein zweites Lambda zurückzugeben?

Zum Beispiel:

public class Person 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 
} 

public class Relation 
{ 
    public int GiverId { get; set; } 
    public int ReceiverId { get; set; } 
} 

public interface IRelationRepository 
{ 
    bool Loves(Expression<Func<Relation, bool>> predicate); 
} 

public class RelationRepository : IRelationRepository 
{ 
    public bool Loves(Expression<Func<Relation, bool>> predicate) 
    { 
     // Some logic... 
     return true; 
    } 
} 

public class KissManager 
{ 
    private readonly IRelationRepository repository; 

    public KissManager(IRelationRepository repository) 
    { 
     this.repository = repository; 
    } 

    public bool Kiss(Person p1, Person p2) 
    { 
     var result = this.repository.Loves(r => r.GiverId == p1.Id && r.ReceiverId == p2.Id) 
      && this.repository.Loves(r => r.GiverId == p2.Id && r.ReceiverId == p1.Id); 
     return result; 
    } 
} 

[TestMethod] 
public void KissWithReceiverNotInLove() 
{ 
    // Arange. 
    var p1 = new Person { Id = 5, Name = "M. Love" }; 
    var p2 = new Person { Id = 17, Name = "Paul Atreid" }; 

    var kissRepositoryMock = new Mock<IRelationRepository>(); 
    kissRepositoryMock 
     .Setup(m => m.Loves(r => r.GiverId == p1.Id && r.ReceiverId == p2.Id)) 
     .Returns(true); 
    kissRepositoryMock 
     .Setup(m => m.Loves(r => r.GiverId == p2.Id && r.ReceiverId == p1.Id)) 
     .Returns(false); 

    var kissManager = new KissManager(kissRepositoryMock.Object); 

    // Act. 
    var result = kissManager.Kiss(p1, p2); 

    // Assert. 
    Assert.IsFalse(result); 
} 
+1

[SetupSequence] (https://codecontracts.info/2011/07/28/moq-setupsequence-is-great-for-mocking/) statt 'Setup'. Stellen Sie jedoch sicher, dass Sie sie in der richtigen Reihenfolge eingerichtet haben. –

+0

Vielen Dank, es funktioniert! Aber wenn ich die Reihenfolge meiner Anrufe (im Manager) ändern, ändert es nichts funktionell, aber mein Test wird fehlgeschlagen. Kennst du einen anderen Weg? – C0b0ll

+1

Die Reihenfolge von SetupSequence muss mit der im SUT übereinstimmen. Wenn Sie die Reihenfolge der Aufrufe in Ihrem SUT ändern, müssen Sie den Test aktualisieren. Die Tests werden in dieser Hinsicht brüchig sein. –

Antwort

2

Eine Option Setup würde das Verfahren jeden Ausdruck/Prädikat über It.IsAny<Expression<Func<Relation, bool>>>() zu akzeptieren und eine gefälschte Datenquelle zu verwenden, das das gewünschte Verhalten mit einem bestimmten Prädikat/Ausdruck erlaubt.

[TestMethod] 
public void _KissWithReceiverNotInLove() { 
    // Arange. 
    var p1 = new Person { Id = 5, Name = "M. Love" }; 
    var p2 = new Person { Id = 17, Name = "Paul Atreid" }; 
    var relations = new List<Relation>() 
    { 
     new Relation{ GiverId = p1.Id, ReceiverId = p2.Id } 
     //The above should satisfy the first expected predicate. 
     //Note there are no other relations in this list. 
     //That is by design to make the second predicate return false. 
    }; 

    var kissRepositoryMock = new Mock<IRelationRepository>(); 

    kissRepositoryMock 
     .Setup(m => m.Loves(It.IsAny<Expression<Func<Relation, bool>>>())) 
     .Returns((Expression<Func<Relation, bool>> predicate) => relations.Any(predicate.Compile())); 

    var kissManager = new KissManager(kissRepositoryMock.Object); 

    // Act. 
    var result = kissManager.Kiss(p1, p2); 

    // Assert. 
    Assert.IsFalse(result); 
} 
+0

Es ist eine sehr gute Möglichkeit, den Datensatz im Repository zu simulieren. Danke für deine Antwort ! – C0b0ll

2

Wie es in dem Kommentar des ersten Post gesagt wird, ist es auch möglich, SetupSequence zu verwenden, aber ich ziehe @Nkosi Lösung, weil es nicht der Implementierung abhängig ist.

Ich poste ein Beispiel für die Verwendung von SetupSequence in unserem Beispiel. Es kann für jemanden nützlich sein.

[TestMethod] 
public void KissWithReceiverNotInLove() 
{ 
    // Arange. 
    var p1 = new Person { Id = 5, Name = "M. Love" }; 
    var p2 = new Person { Id = 17, Name = "Paul Atreid" }; 

    var kissRepositoryMock = new Mock<IRelationRepository>(); 
    kissRepositoryMock 
     .SetupSequence(m => m.Loves(It.IsAny<Expression<Func<Relation, bool>>>())) 
     .Returns(true) 
     .Returns(false); 

    var kissManager = new KissManager(kissRepositoryMock.Object); 

    // Act. 
    var result = kissManager.Kiss(p1, p2); 

    // Assert. 
    Assert.IsFalse(result); 
} 
Verwandte Themen