2013-12-13 16 views
9

Sto provando a eseguire alcuni test sulla mia applicazione MVC ma ho avuto un mondo di difficoltà a farlo funzionare. Cercherò di arrivare subito al punto:Come simulare o falsificare HttpApplication/HttpContext per i test

sto usando RhinoMocks per provare qualcosa di simile:

Setup:

MockRepository mocks = new MockRepository(); 
HttpContextBase _mockContext = mocks.FakeHttpContext(); 
mocks.SetFakeControllerContext(new LoginController()); 
HttpApplicationStateBase appState = MockRepository.GenerateStub<HttpApplicationStateBase>(); 
_mockContext.Expect(mc => mc.Application).Return(appState); 
HttpContext.Current = _mockContext.ApplicationInstance.Context; 

Ecco il metodo FakeHttpContext():

public static HttpContextBase FakeHttpContext(this MockRepository mocks) 
{ 
    HttpApplication app = mocks.PartialMock<HttpApplication>(); 

    HttpContextBase context = mocks.PartialMock<HttpContextBase>(); 
    HttpRequestBase request = mocks.PartialMock<HttpRequestBase>(); 
    HttpResponseBase response = mocks.PartialMock<HttpResponseBase>(); 
    HttpSessionStateBase session = mocks.PartialMock<HttpSessionStateBase>(); 
    HttpServerUtilityBase server = mocks.PartialMock<HttpServerUtilityBase>(); 

    SetupResult.For(context.ApplicationInstance).Return(app); 

    SetupResult.For(context.Request).Return(request); 
    SetupResult.For(context.Response).Return(response); 
    SetupResult.For(context.Session).Return(session); 
    SetupResult.For(context.Server).Return(server); 

    mocks.Replay(context); 
    return context; 
} 

Devo davvero accedere a HttpContextBase.Request.AppRelativeCurrentExecutionFilePath ma viene sempre restituito come null. Lo stesso vale per HttpContext.Current.Request.RequestContext.

Qualcuno può aiutarmi qui? È sicuro di dire che sono disperato a questo punto.

+0

È non dire qual è il problema? Hai un errore (quale?)? Per quanto posso vedere, l'impostazione specifica 'Setup (c => c.Request.AppRelativeCurrentExecutionFilePath) 'dovrebbe funzionare perché' Request' è una proprietà 'virtuale' di un tipo che ha a sua volta una proprietà' virtuale' 'AppRelativeCurrentExecutionFilePath'. Qual è la tua ragione per dire '_mockContext.SetupAllProperties();'? Che vuoi che siano impostate anche * altre * proprietà? –

+0

@JeppeStigNielsen Ho aggiornato la mia domanda con quello che sto usando ora. Non riesco ancora a farlo funzionare. – Kehlan

risposta

1

Prima di tutto, prova a evitare di utilizzare HttpContext.Current poiché l'utilizzo di un metodo statico rende molto più difficile da testare come hai scoperto ora. Se si utilizza un framework di iniezione delle dipendenze, inserire HttpContextBase nel costruttore.

Per il vostro problema reale, in FakeHttpContext() provare a cambiare

HttpRequestBase request = mocks.PartialMock<HttpRequestBase>(); 

a

HttpRequestBase request = mocks.GenerateStub<HttpRequestBase>(); 

e poi nel vostro test che si può fare qualcosa di simile:

_mockContext.Request.Stub(x=> x.AppRelativeCurrentExecutionFilePath).Return("foo"); 
var result = object.DoSomething(); 
Assert.AreEqual("foo",result); 

I don Penso che sia abbastanza utile fare il mocking parziale su HttpContext come si testerà il fra mework invece (es. verifica che il framework restituisca il valore corretto X in base al valore Y e Z nel HttpContext)

Un'altra alternativa è creare una classe wrapper attorno a HttpContextBase che restituisca i valori calcolati. Per esempio. HttpContextBaseWrapper.AppRelativeCurrentExecutionFilePath(), HttpContextBaseWrapper.RequestIpAddress(). Questo renderà il test TUTTE le altre classi meno complicate in quanto non devono preoccuparsi di deridere HttpContextBase ei dettagli, devono semplicemente prendere in giro la tua classe HttpContextBaseWrapper.

Edit:

Mi piacerebbe anche che si consiglia di iniettare il vostro HttpRequestContext pure, ma se questo non è possibile, allora si può stub RequestContext in questo modo nel metodo FakeHttpContext:

var requestContext = MockRepository.GenerateStub<RequestContext>(); 
request.RequestContext = requestContext; 
+0

Apprezzo molto questa risposta. Ho modificato l'OP, poiché ho incontrato un altro problema. Devo anche prendere in giro 'HttpContext.Current.Request.RequestContext'. Qualche possibilità che tu mi aiuti anche con quello? – Kehlan

+0

Ho aggiornato la mia risposta per consentire all'utente di stubare RequestContext. –

+0

Non sono abbastanza sicuro di cosa sia 'HttpRequestContext'. Immagino che tu intenda "RequestContext". Grazie ancora! Lo proverò e vedrò come va. – Kehlan

1

Perché non si crea una classe di astrazione che contiene chiamate alla base HttpContext?

Poi si può fare qualcosa di simile:

public class MyClass 
{ 
    private readonly IHttpContext _httpContext; 
    MyClass(IHttpContext httpContext) 
    { 
     _httpContext = httpContext; 
    } 

    public void Blaat() 
    { 
     _httpContext.DoYourThingsWithTheHttpContext(); 
    } 
} 

Supponendo che si sta utilizzando l'iniezione di dipendenza, altrimenti guardare il quadro falsi e Stubs da Microsoft.