unit-testing
Test-Doubles
Suche…
Bemerkungen
Beim Testen ist es manchmal nützlich, ein Test-Double zu verwenden, um das Verhalten des getesteten Systems zu manipulieren oder zu überprüfen. Die Doubles werden in die Klasse oder Methode, die getestet wird, anstelle von Produktionscode übergeben oder eingefügt .
Verwenden eines Stubs zur Bereitstellung von Dosenantworten
Bei einem Stub handelt es sich um ein Test-Double mit geringem Gewicht, das beim Aufruf von Methoden vorgefertigte Antworten liefert. Wenn eine getestete Klasse von einer Schnittstelle oder Basisklasse abhängt, kann eine alternative 'Stub'-Klasse zum Testen implementiert werden, die der Schnittstelle entspricht.
Also, unter der Annahme der folgenden Schnittstelle,
public interface IRecordProvider {
IEnumerable<Record> GetRecords();
}
Wenn die folgende Methode getestet werden sollte
public bool ProcessRecord(IRecordProvider provider)
Eine Stub-Klasse, die die Schnittstelle implementiert, kann geschrieben werden, um bekannte Daten an die getestete Methode zurückzugeben.
public class RecordProviderStub : IRecordProvider
{
public IEnumerable<Record> GetRecords()
{
return new List<Record> {
new Record { Id = 1, Flag=false, Value="First" },
new Record { Id = 2, Flag=true, Value="Second" },
new Record { Id = 3, Flag=false, Value="Third" }
};
}
}
Diese Stub-Implementierung kann dann dem getesteten System zur Verfügung gestellt werden, um dessen Verhalten zu beeinflussen.
var stub = new RecordProviderStub();
var processed = sut.ProcessRecord(stub);
Verwenden eines spöttischen Rahmens als Stichleitung
Die Begriffe Mock und Stub können oft verwirrt werden. Ein Grund dafür ist, dass viele Mocking-Frameworks auch die Erstellung von Stubs ohne den mit Mocking verbundenen Überprüfungsschritt unterstützen.
Anstatt eine neue Klasse zu schreiben, um einen Stub wie im Beispiel "Verwenden eines Stubs zum Bereitstellen von Antworten aus Dosen" zu implementieren, können stattdessen Mock-Frameworks verwendet werden.
Moq verwenden:
var stub = new Mock<IRecordProvider>();
stub.Setup(provider => provider.GetRecords()).Returns(new List<Record> {
new Record { Id = 1, Flag=false, Value="First" },
new Record { Id = 2, Flag=true, Value="Second" },
new Record { Id = 3, Flag=false, Value="Third" }
});
Dadurch wird dasselbe Verhalten wie mit dem handcodierten Stub erreicht und auf ähnliche Weise an das zu testende System geliefert:
var processed = sut.ProcessRecord(stub.Object);
Verwendung eines Mocking-Frameworks zur Überprüfung des Verhaltens
Mocks werden verwendet, wenn die Wechselwirkungen zwischen dem getesteten System und Testverdoppelungen überprüft werden müssen. Es muss sorgfältig darauf geachtet werden, dass nicht zu spröde Tests erstellt werden. Spottungen können jedoch besonders nützlich sein, wenn die zu testende Methode einfach andere Anrufe koordiniert.
Dieser Test überprüft , dass , wenn das Verfahren im Test genannt wird ( ProcessRecord
), dass die Service - Methode ( UseValue
) für die aufgerufen wird Record
wo Flag==true
. Dazu wird ein Stub mit Daten aus der Datenbank eingerichtet:
var stub = new Mock<IRecordProvider>();
stub.Setup(provider => provider.GetRecords()).Returns(new List<Record> {
new Record { Id = 1, Flag=false, Value="First" },
new Record { Id = 2, Flag=true, Value="Second" },
new Record { Id = 3, Flag=false, Value="Third" }
});
Dann wird ein Mock eingerichtet, der die IService
Schnittstelle implementiert:
var mockService = new Mock<IService>();
mockService.Setup(service => service.UseValue(It.IsAny<string>())).Returns(true);
Diese werden dann an das zu testende System geliefert und die zu testende Methode wird aufgerufen.
var sut = new SystemUnderTest(mockService.Object);
var processed = sut.ProcessRecord(stub.Object);
Das Mock kann dann abgefragt werden, um zu überprüfen, ob der erwartete Anruf angefordert wurde. In diesem Fall ein Aufruf von UseValue
mit einem Parameter "Second", dem Wert aus dem Datensatz, bei dem Flag==true
.
mockService.Verify(service => service.UseValue("Second"));