Frage

Der Controller-Kontext hängt also von einigen asp.net-Interna ab.Welche Möglichkeiten gibt es, diese für Unit-Tests sauber nachzubilden?Scheint, als ob es sehr einfach ist, Tests mit Unmengen an Setup zu verstopfen, wenn ich beispielsweise nur Request.HttpMethod benötige, um „GET“ zurückzugeben.

Ich habe einige Beispiele/Helfer im Internet gesehen, aber einige sind veraltet.Ich dachte, das wäre ein guter Ort, um das Neueste und Beste aufzubewahren.

Ich verwende die neueste Version von Rhino Mocks

War es hilfreich?

Lösung

Mit MoQ sieht es in etwa so aus:

var request = new Mock<HttpRequestBase>();
request.Expect(r => r.HttpMethod).Returns("GET");
var mockHttpContext = new Mock<HttpContextBase>();
mockHttpContext.Expect(c => c.Request).Returns(request.Object);
var controllerContext = new ControllerContext(mockHttpContext.Object
, new RouteData(), new Mock<ControllerBase>().Object);

Ich denke, die Syntax von Rhino Mocks ist ähnlich.

Andere Tipps

Hier ist eine Beispiel-Unit-Test-Klasse mit MsTest und Moq, die HttpRequest- und HttpResponse-Objekte verspottet.(.NET 4.0, ASP.NET MVC 3.0)

Die Controller-Aktion ruft den Wert aus der Anfrage ab und legt den HTTP-Header in den Antwortobjekten fest.Andere http-Kontextobjekte könnten auf ähnliche Weise nachgeahmt werden

[TestClass]
public class MyControllerTest
{
    protected Mock<HttpContextBase> HttpContextBaseMock;
    protected Mock<HttpRequestBase> HttpRequestMock;
    protected Mock<HttpResponseBase> HttpResponseMock;

    [TestInitialize]
    public void TestInitialize()
    {
        HttpContextBaseMock = new Mock<HttpContextBase>();
        HttpRequestMock = new Mock<HttpRequestBase>();
        HttpResponseMock = new Mock<HttpResponseBase>();
        HttpContextBaseMock.SetupGet(x => x.Request).Returns(HttpRequestMock.Object);
        HttpContextBaseMock.SetupGet(x => x.Response).Returns(HttpResponseMock.Object);
    }

    protected MyController SetupController()
    {
        var routes = new RouteCollection();
        var controller = new MyController();
        controller.ControllerContext = new ControllerContext(HttpContextBaseMock.Object, new RouteData(), controller);
        controller.Url = new UrlHelper(new RequestContext(HttpContextBaseMock.Object, new RouteData()), routes);
        return controller;
    }

    [TestMethod]
    public void IndexTest()
    {
        HttpRequestMock.Setup(x => x["x"]).Returns("1");
        HttpResponseMock.Setup(x => x.AddHeader("name", "value"));

        var controller = SetupController();
        var result = controller.Index();
        Assert.AreEqual("1", result.Content);

        HttpRequestMock.VerifyAll();
        HttpResponseMock.VerifyAll();
    }
}

public class MyController : Controller
{
    public ContentResult Index()
    {
        var x = Request["x"];
        Response.AddHeader("name", "value");
        return Content(x);
    }
}

Hier ist ein Ausschnitt aus Jasons Link.Es ist die gleiche wie Phils Methode, verwendet jedoch Rhino.

Notiz:„mockHttpContext.Request“ wird gestuft, um „mockRequest“ zurückzugeben Vor Die Interna von mockRequest sind ausgeblendet.Ich glaube, dass diese Anordnung erforderlich ist.

// create a fake web context
var mockHttpContext = MockRepository.GenerateMock<HttpContextBase>();
var mockRequest = MockRepository.GenerateMock<HttpRequestBase>();
mockHttpContext.Stub(x => x.Request).Return(mockRequest);

// tell the mock to return "GET" when HttpMethod is called
mockRequest.Stub(x => x.HttpMethod).Return("GET");            

var controller = new AccountController();

// assign the fake context
var context = new ControllerContext(mockHttpContext, 
                  new RouteData(), 
                  controller);
controller.ControllerContext = context;

// act
...

Das Verfahren hierfür scheint sich in MVC2 leicht geändert zu haben (ich verwende RC1).Die Lösung von Phil Haack funktioniert bei mir nicht, wenn die Aktion eine bestimmte Methode erfordert ([HttpPost], [HttpGet]).Wenn man sich in Reflector umschaut, sieht es so aus, als hätte sich die Methode zur Überprüfung dieser Attribute geändert.MVC prüft jetzt request.Headers, request.Form, Und request.QueryString Für ein X-HTTP-Method-Override Wert.

Wenn Sie Mocks für diese Eigenschaften hinzufügen, funktioniert es:

var request = new Mock<HttpRequestBase>();
request.Setup(r => r.HttpMethod).Returns("POST");
request.Setup(r => r.Headers).Returns(new NameValueCollection());
request.Setup(r => r.Form).Returns(new NameValueCollection());
request.Setup(r => r.QueryString).Returns(new NameValueCollection());

var mockHttpContext = new Mock<HttpContextBase>();
mockHttpContext.Expect(c => c.Request).Returns(request.Object);
var controllerContext = new ControllerContext(mockHttpContext.Object, new RouteData(), new Mock<ControllerBase>().Object);

Oder Sie können dies mit Typemock Isolator tun, ohne überhaupt einen gefälschten Controller einsenden zu müssen:

Isolate.WhenCalled(()=>HttpContext.Request.HttpMethod).WillReturn("Get");

Ich bin mit dieser Spezifikation fertig

public abstract class Specification <C> where C: Controller
{
    protected C controller;

    HttpContextBase mockHttpContext;
    HttpRequestBase mockRequest;

    protected Exception ExceptionThrown { get; private set; }

    [SetUp]
    public void Setup()
    {
        mockHttpContext = MockRepository.GenerateMock<HttpContextBase>();
        mockRequest = MockRepository.GenerateMock<HttpRequestBase>();

        mockHttpContext.Stub(x => x.Request).Return(mockRequest);
        mockRequest.Stub(x => x.HttpMethod).Return("GET");


        EstablishContext();
        SetHttpContext();

        try
        {
            When();
        }
        catch (Exception exc)
        {
            ExceptionThrown = exc;
        }
    }

    protected void SetHttpContext()
    {
        var context = new ControllerContext(mockHttpContext, new RouteData(), controller);
        controller.ControllerContext = context;
    }

    protected T Mock<T>() where T: class
    {
        return MockRepository.GenerateMock<T>();
    }

    protected abstract void EstablishContext();
    protected abstract void When();

    [TearDown]
    public virtual void TearDown()
    {
    }
} 

und der Saft ist da

[TestFixture]
public class When_invoking_ManageUsersControllers_Update :Specification   <ManageUsersController>
{
    private IUserRepository userRepository;
    FormCollection form;

    ActionResult result;
    User retUser;

    protected override void EstablishContext()
    {
        userRepository = Mock<IUserRepository>();
        controller = new ManageUsersController(userRepository);

        retUser = new User();
        userRepository.Expect(x => x.GetById(5)).Return(retUser);
        userRepository.Expect(x => x.Update(retUser));

        form = new FormCollection();
        form["IdUser"] = 5.ToString();
        form["Name"] = 5.ToString();
        form["Surename"] = 5.ToString();
        form["Login"] = 5.ToString();
        form["Password"] = 5.ToString();
    }

    protected override void When()
    {
        result = controller.Edit(5, form);
    }

    [Test]
    public void is_retrieved_before_update_original_user()
    {
        userRepository.AssertWasCalled(x => x.GetById(5));
        userRepository.AssertWasCalled(x => x.Update(retUser));
    }
}

genießen

Ich finde, dass diese lange Spottprozedur zu viel Reibung verursacht.

Der beste Weg, den wir gefunden haben – die Verwendung von ASP.NET MVC für ein echtes Projekt – besteht darin, den HttpContext in eine IWebContext-Schnittstelle zu abstrahieren, die einfach durchläuft.Dann können Sie den IWebContext ohne Probleme verspotten.

Hier ist ein Beispiel

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top