2016-07-03 3 views
1

Ich habe folgende Web-API-Controller-Methode.HttpContext.Current ist null, wenn Unit-Test

Wenn ich diesen Code über das Web ausführen, ist HttpContext.Currentnever null und geben Sie den gewünschten Wert.

public override void Post([FromBody]TestDTO model) 
{ 

    var request = HttpContext.Current.Request; 
    var testName = request.Headers.GetValues("OS Type")[0]; 
    // more code 

} 

Allerdings, wenn ich diese Methode von Unit Test nennen, HttpContext.Current is always null.

Wie kann ich das Problem beheben?

+0

Es macht Sinn, wenn Sie eine Controller-Methode aus einem Testprojekt aufrufen. Es gibt keinen http-Kontext, da Sie keine Webanwendung ausführen. Lösung ist, die Anfrage zu verspotten. – derloopkat

+0

Wie verspottet es die Anfrage? Kannst du ein einfaches Beispiel teilen? – simbada

+0

http://stackoverflow.com/questions/3195839/asp-net-mvc-rhino-mocks-mocking-httprequest-values ​​ – derloopkat

Antwort

8

Während Komponententests ist HttpContext immer null, da es normalerweise von IIS aufgefüllt wird. Sie haben ein paar Optionen dazu.

Natürlich könnten Sie die HttpContext verspotten, (die Sie nicht wirklich tun sollten - Don't mock HttpContext !!!! Er läßt sich nicht spotten werden mag,!) ,. Sie sollten wirklich versuchen, weg von enger Kopplung mit HttpContext überall in Ihrem Code zu bleiben. Versuchen Sie, es auf einen zentralen Bereich (SRP) zu beschränken;

Stattdessen herausfinden, was die Funktionalität ist, die Sie erreichen möchten, und eine Abstraktion entwerfen. Dadurch wird Ihr Code testbarer, da er nicht so eng an HttpContext gekoppelt ist.

Anhand Ihres Beispiels suchen Sie nach Headerwerten. Dies ist nur ein Beispiel dafür, wie Sie Ihr Denken bei der Verwendung von HttpContext ändern können.

Ihre ursprüngliche Beispiel hat dieses

var request = HttpContext.Current.Request; 
var testName = request.Headers.GetValues("OS Type")[0]; 

Wenn Sie etwas suchen, wie dieses

var testName = myService.GetOsType(); 

Na dann einen Dienst erstellen, dass

public interface IHeaderService { 
    string GetOsType(); 
} 

bietet, die eine haben könnte konkrete Implementierung wie

public class MyHeaderService : IHeaderService { 

    public string GetOsType() { 
     var request = HttpContext.Current.Request; 
     var testName = request.Headers.GetValues("OS Type")[0]; 
     return testName; 
    } 
} 

Jetzt in Ihrem Controller können Sie Ihre Abstraktion haben stattdessen eine enge Kopplung an HttpContext

public class MyApiController : ApiController { 
    IHeaderService myservice; 
    public MyApiController(IHeaderService headers) { 
     myservice = headers; 
    } 

    public IHttpActionResult Post([FromBody]TestDTO model) {  
     var testName = myService.GetOsType(); 
     // more code 

    }  
} 

des Habens können Sie später Ihre konkreten Typ injizieren, um die Funktionalität, die Sie wollen zu bekommen.

Zum Testen tauschen Sie dann Abhängigkeiten aus, um Ihren Test auszuführen.

Wenn die Methode im Test Ihre Post() Methode ist, können Sie eine gefälschte Abhängigkeit erstellen oder einen Mockframework verwenden

[TestClass] 
public class MyTestClass { 

    public class MyFakeHeaderService : IHeaderService { 
     string os; 
     public MyFakeHeaderService(string os) { 
      this.os = os; 
     } 

     public string GetOsType() { 
      return os; 
     } 
    } 

    [TestMethod] 
    public void TestPostMethod() { 
     //Arrange 
     IHeaderService headers = new MyFakeHeaderService("FAKE OS TYPE"); 
     var sut = new MyApiController(headers); 
     var model = new TestDTO(); 

     //Act 
     sut.Post(model); 

     //Assert 
     //..... 
    } 
} 
+0

Ausgezeichnete Antwort und Erklärung. Ich verstehe Ihren Standpunkt und kann mein Problem lösen. Danke – simbada

0

Das ist von Entwurf und es ist immer null sein. Aber es gibt ein FakeHttpContext Projekt auf Nuget und einfach können Sie es verwenden.

FakeHttpContext So installieren Sie den folgenden Befehl in dem Package Manager Console (PMC)

Install-Package FakeHttpContext 

laufen und es dann wie folgt verwenden:

using (new FakeHttpContext()) 
{ 
HttpContext.Current.Session["mySession"] = "This is a test";  
} 

Besuchen https://www.nuget.org/packages/FakeHttpContext/

Hoffnung das wird helfen :)

-1

Eine gute Referenz von 2014: https://docs.microsoft.com/en-us/aspnet/web-api/overview/advanced/dependency-injection

Dies hat einige andere wesentliche Details wie Inversion of Control, die Sie Ihre benutzerdefinierten Kontextklasse aufrufen können während der Controller Instanziierung.

+0

Der verlinkte Beitrag scheint nicht mit HttpContext.Current verwandt zu sein, oder? – anre

+0

Newbie scheitern, ich konnte die ausgewählte Antwort nicht kommentieren und machte es in meiner eigenen Antwort nicht deutlich genug, dass ich die ausgewählte Antwort ergänzte. Grundsätzlich muss die Antwort Informationen darüber enthalten, wie der neue Service im Konstruktor vom System aufgerufen wird – kskid19

Verwandte Themen