Ich hoffe, diese Frage gibt einige interessante Antworten, weil sie mich eine Weile nervt.
Gibt es einen echten Wert beim Unit-Testen eines Controllers in ASP.NET MVC?
Was ich damit meine, ist, dass meine Controller-Methoden die meiste Zeit (und ich bin kein Genie) selbst in ihrer komplexesten Form so aussehen:
public ActionResult Create(MyModel model)
{
// start error list
var errors = new List<string>();
// check model state based on data annotations
if(ModelState.IsValid)
{
// call a service method
if(this._myService.CreateNew(model, Request.UserHostAddress, ref errors))
{
// all is well, data is saved,
// so tell the user they are brilliant
return View("_Success");
}
}
// add errors to model state
errors.ForEach(e => ModelState.AddModelError("", e));
// return view
return View(model);
}
Das meiste Heben erfolgt entweder über die MVC-Pipeline oder über meine Servicebibliothek.
Vielleicht sollten Sie also folgende Fragen stellen:
- Was wäre es wert, diese Methode in Einheiten zu testen?
- Würde es nicht auf
Request.UserHostAddress
undModelState
mit einer NullReferenceException brechen? Sollte ich versuchen, diese zu verspotten? - Wenn ich diese Methode in einen wiederverwendbaren "Helfer" umwandle (was ich wahrscheinlich tun sollte, wenn ich bedenke, wie oft ich es mache!), lohnt es sich sogar zu testen, wenn alles, was ich wirklich teste, hauptsächlich die "Pipeline" ist, die Wurde es vermutlich von Microsoft auf einen Zentimeter genau getestet?
Ich denke, mein Punkt ist wirklich , das Folgende zu tun, scheint völlig sinnlos und falsch zu sein
[TestMethod]
public void Test_Home_Index()
{
var controller = new HomeController();
var expected = "Index";
var actual = ((ViewResult)controller.Index()).ViewName;
Assert.AreEqual(expected, actual);
}
Offensichtlich bin ich mit diesem übertrieben sinnlosen Beispiel stumpf, aber hat jemand Weisheit, die er hier hinzufügen kann?
Freue mich drauf ... Danke.
c#
unit-testing
asp.net-mvc
LiverpoolsNumber9
quelle
quelle
Antworten:
Selbst für etwas so Einfaches wird ein Komponententest mehreren Zwecken dienen
Für diese spezielle Aktion würde ich Folgendes testen
Sie haben darauf hingewiesen, dass Sie Request und Model auf NullReferenceException überprüft haben, und ich denke, dass ModelState.IsValid sich um die Behandlung von NullReference for Model kümmert.
Durch das Verspotten der Anforderung können Sie sich gegen eine Nullanforderung schützen, die meiner Meinung nach in der Produktion im Allgemeinen unmöglich ist, aber in einem Komponententest auftreten kann. In einem Integrationstest können Sie unterschiedliche UserHostAddress-Werte angeben. (Eine Anforderung ist immer noch eine Benutzereingabe für das Steuerelement und sollte dementsprechend getestet werden.)
quelle
Meine Controller sind ebenfalls sehr klein. Der größte Teil der "Logik" in Controllern wird mithilfe von Filterattributen (integriert und handgeschrieben) verarbeitet. Daher hat mein Controller normalerweise nur eine Handvoll Jobs:
ActionResult
Die meisten Modellbindungen werden automatisch von ASP.NET MVC durchgeführt. DataAnnotations übernehmen auch für mich den größten Teil der Validierung.
Selbst wenn ich so wenig zu testen habe, schreibe ich sie normalerweise immer noch. Grundsätzlich teste ich, ob meine Repositorys aufgerufen werden und der richtige
ActionResult
Typ zurückgegeben wird. Ich habe eine bequeme Methode, umViewResult
sicherzustellen, dass der richtige Ansichtspfad zurückgegeben wird und das Ansichtsmodell so aussieht, wie ich es erwartet habe. Ich habe einen anderen, um zu überprüfen, ob der richtige Controller / die richtige Aktion eingestellt istRedirectToActionResult
. Ich habe andere Tests fürJsonResult
usw. usw.Eine unglückliche Folge der Unterklassifizierung der
Controller
Klasse ist, dass sie viele praktische Methoden bietet, dieHttpContext
intern verwendet werden. Dies macht es schwierig, die Steuerung einem Komponententest zu unterziehen. Aus diesem Grund setze ich normalerweiseHttpContext
-abhängige Aufrufe hinter eine Schnittstelle und übergebe diese Schnittstelle an den Konstruktor des Controllers (ich verwende die Ninject-Web-Erweiterung, um meine Controller für mich zu erstellen). Auf dieser Oberfläche werden normalerweise die Eigenschaften des Hilfsprogramms für den Zugriff auf die Sitzung, die Konfigurationseinstellungen, das IP-Prinzip und die URL-Hilfsprogramme festgelegt.Dies erfordert viel Sorgfalt, aber ich denke, es lohnt sich.
quelle
BaseControllerTests
Klasse, in der alle leben. Ich verspotte meine Repositories. Ich schließe sie mit Ninject an.ActionResult
s einfach , um die übergebenen URLs, Modelle usw. zu überprüfenOffensichtlich sind einige Controller sehr viel komplexer, basieren aber nur auf Ihrem Beispiel:
Was passiert, wenn myService eine Ausnahme auslöst?
Als Randnotiz.
Außerdem würde ich die Weisheit in Frage stellen, eine Liste als Referenz zu übergeben (dies ist nicht erforderlich, da c # ohnehin als Referenz übergeben wird, auch wenn dies nicht der Fall ist) - eine errorAction-Aktion (Action) übergeben, an die der Dienst dann Fehlermeldungen senden kann Dies könnte dann geschehen, wie Sie möchten (vielleicht möchten Sie es der Liste hinzufügen, vielleicht möchten Sie einen Modellfehler hinzufügen, vielleicht möchten Sie es protokollieren).
In deinem Beispiel:
Anstelle von Referenzfehlern geben Sie beispielsweise (string s) => ModelState.AddModelError ("", s) ein.
quelle