Ich bin auch kein Experte, und ich habe nur TDD für eine kleine Weile, also nehmen Sie, was ich schreibe in dieser weitläufigen Antwort mit einem Löffel Salz :) Ich bin sicher, jemand anderes kann darauf hinweisen, wenn ich ' Ich habe wirklich schlechte Fehler gemacht oder dich in die falsche Richtung gelenkt ...
Ich bin mir nicht sicher, ob dein Test wirklich ein Komponententest ist, weil er mehrere Abhängigkeiten ausübt. Angenommen, Sie führen diesen Test aus und erhalten eine Ausnahme, die aus der Methode ausgeschlossen wird. Hat diese Ausnahme kommen aus
- RepositoryHelper.GetTake2Repository()) werfen? (Depencenz-Problem)
- ProjectCrewsByProjectSpec Konstruktor werfen? (Abhängigkeitsproblem)
- rep.GetList (spec) werfen? der Kendo (es ist kendo, richtig?) (Abhängigkeitsproblem)
- ToDataSourceResult() werfen? (Behavioral Ausgabe)
Unit-Tests ist alles über das Testen Dinge in völligen Isolation von ihren Abhängigkeiten, so im Moment würde ich sagen, es ist eher wie ein Integrationstest, wodurch Sie wirklich wie die Systeme nicht kümmern interagieren, möchten Sie nur sicherstellen, dass für eine bestimmte projectID, seasonId und episodeId Sie erhalten die erwarteten Ergebnisse zurück - in diesem Fall, was wirklich rep.GetList() Methode in Verbindung mit der sind. ToDataSourceResult Erweiterung.
Jetzt sind Integrationstests sehr nützlich und 100% erforderlich als Teil einer testgetriebenen Methode, und wenn Sie das wirklich tun möchten, dann machen Sie es richtig (ich setze dieses in und erwarten dass zurück, habe ich dass zurück)
Aber wenn Sie wollen Unit Test dieser Code (genauer gesagt, wenn Sie an die Einheit wollen Ihre Klassen testen GetProjectBySpec Methode) Sie haben? zu tun, wie @jimmy_keen erwähnt und es umgestalten, so dass Sie dietesten können 210 Verhalten von GetProjectBySpec. z.B. hier ist ein spezifiziertes Verhalten gerade erfunden, ich natürlich könnten Sie anders sein:
- Wenn Eingang schlecht, wirft Argument
- ein neues ProjectCrewsByProjectSpec Objekt erstellt
- rep.GetList Anrufe und leitet spec es
- Gibt eine nicht-null-DataSourceResult
Das erste, was Sie tun müssen, um in der Lage zu testen, dass GetProjectBySpec all die Dinge, die in dieser Liste tut, ist es zu Refactoring so dass es keine eigenen Abhängigkeiten erzeugt - stattdessen geben Sie ihm die Abhängigkeiten, die es benötigt, über Dependency Injection.
DI wirklich funktioniert am besten, wenn Sie von Schnittstelle injizieren, so lautet, unabhängig Klasse diese Methode bietet, Konstruktor für diese Klasse soll für eine Instanz nehmen Beispiel IRepositoryHelper und speichert sie in einem privaten Nur-Lese-Mitglied. Es sollte auch eine Instanz von IProjectCrewsByProjectSpecFactory, die Sie verwenden würden, um Ihre Spezifikation zu erstellen.Jetzt, da Sie testen wollen, was GetProjectBySpec tatsächlich mit diesen Abhängigkeiten tut, dann werden Sie ein spöttisches Framework wie Moq verwenden, auf das ich hier nur im folgenden Beispiel nicht eingehen werde.
Wenn keine dieser Klassen derzeit eine solche Schnittstelle implementiert, verwenden Sie einfach Visual Studio, um die Schnittstellendefinition für Sie basierend auf der Klassendefinition zu extrahieren. Wenn es sich um Drittklassen handelt, auf die Sie keinen Einfluss haben, könnte dies schwierig sein.
Aber nehmen wir einmal an, dass Sie Schnittstellen so definieren können: T '' s sollte gehen ...) Code unten ist nicht getestet oder auf Tippfehler überprüft!
public interface IRepositoryHelper<ProjectDGACrew>
{
IList<ProjectDGACrew> GetList(IProjectCrewsByProjectSpecFactory spec);
}
public interface IProjectCrewsByProjectSpecFactory
{
ProjectDGACrew Create(int projectId, int seasonId, int episodeId);
}
Ihr Code würde dann so etwas wie dies am Ende aussehen:
//somewhere in your class definition
private readonly IRepositoryHelper<T> repo;
private readonly IProjectCrewsByProjectSpecFactory pfactory;
//constructor
public MyClass(IRepositoryHelper<ProjectDGACrew> repo, IProjectCrewsByProjectSpecFactory pfactory)
{
this.repo = repo;
this.pfactory=pfactory;
}
//method to be tested
public DataSourceResult GetProjectBySpec(int projectId, int seasonId, int episodeId)
{
var spec = pfactory.Create(projectId, seasonId, episodeId);
var personList = repo.GetList(spec).Select(p => new
{//big query...}).ToDataSourceResult();
return personList;
}
jetzt haben Sie 4 Prüfverfahren schreiben:
[TestMethod]
[ExepctedException(typeof(ArgumentException)]
public void SUT_WhenInputIsBad_ThrowsArgumentException()
{
var sut = new MyClass(null,null); //don't care about our dependencies for this check
sut.GetProjectBySpec(0,0,0); //or whatever is invalid input for you.
//don't care about the return, only that the method throws.
}
[TestMethod]
public void SUT_WhenInputIsGood_CreatesProjectCrewsByProjectSpec()
{
//create dependencies using Moq framework.
var pf= new Mock<IProjectCrewsByProjectSpecFactory>();
var repo = new Mock<IRepository<ProjectDgaCrew>>();
//setup such that a call to pfactory.Create in the tested method will return nothing
//because we actually don't care about the result - only that the Create method is called.
pf.Setup(p=>p.Create(1,2,3)).Returns<ProjectDgaCrew>(new ProjectDgaCrew());
//setup the repo such that any call to GetList with any ProjectDgaCrew object returns an empty list
//again we do not care about the result.
//This mock dependency is only being used here
//to stop an exception being thrown from the test method
//you might want to refactor your behaviours
//to specify an early exit from the function when the factory returns a null object for example.
repo.Setup(r=>r.GetList(It.IsAny<ProjectDgaCrew>()).Returns<IList<ProjectDGACrew>>(new List<ProjectDgaCrew>());
//create our System under test, inject our mock objects:
var sut = new MyClass(repo,pf.Object);
//call the method:
sut.GetProjectBySpec(1,2,3);
//and verify that it did indeed call the factory.Create method.
pf.Verify(p=>p.Create(1,2,3),"pf.Create was not called with 1,2,3");
}
public void SUT_WhenInputIsGood_CallsRepoGetList(){} //you get the idea
public void SUT_WhenInputIsGood_ReturnsNonNullDataSourceResult(){}//and so on.
Hoffnung, dass Sie etwas Hilfe gibt ... und natürlich können Sie Ihre Testklassen umgestalten, um viel von der spöttischen Installation zu vermeiden, und alles an einem einzigen Ort haben, um die Codezeilen auf ein Minimum zu beschränken.
Ich bin auch ein Unit-Test-Noob, aber meine Annahme ist, dass Sie bereits wissen, was Sie * sollten * zurück von der Methode erhalten, wenn Sie diese Eingaben eingeben. Vergleichen Sie das mit dem, was Sie * tatsächlich * zurückbekommen, um festzustellen, ob der Komponententest erfolgreich ist. – MadHenchbot
also im Grunde für eine Abfrage testen ist wertlos nein? da die Daten die ganze Zeit ändern können. –
Wenn dies der Fall ist, müssen Sie möglicherweise die Datenbank nachbilden, um jedes Mal zuverlässige Ergebnisse zu erhalten. Da ich nicht positiv bin, werde ich einfach Ihre Frage +1 geben und darauf warten, dass sich jemand sachkundiger einwiegt. :) – MadHenchbot