69

したがって、コントローラーのコンテキストは、いくつかの asp.net 内部に依存します。単体テスト用にこれらをきれいにモックアップする方法は何ですか? たとえば、「GET」を返すための Request.HttpMethod のみが必要な場合、大量のセットアップでテストを詰まらせるのは非常に簡単なようです。

ネットでいくつかの例/ヘルパーを見てきましたが、古いものもあります。これは、最新かつ最高のものを保持するのに適した場所であると考えました.

最新バージョンの rhino モックを使用しています

4

7 に答える 7

65

MoQ を使用すると、次のようになります。

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);

Rhino Mocks の構文も似ていると思います。

于 2008-08-28T16:06:37.890 に答える
21

HttpRequest および HttpResponse オブジェクトをモックする MsTest および Moq を使用した単体テスト クラスの例を次に示します。(.NET 4.0、ASP.NET MVC 3.0)

コントローラ アクションは、リクエストから値を取得し、レスポンス オブジェクトに http ヘッダーを設定します。他の http コンテキスト オブジェクトも同様の方法でモックアップできます

[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);
    }
}
于 2013-02-22T04:37:50.547 に答える
19

これがJasonのリンクからの抜粋です。Philの方法と同じですが、rhinoを使用します。

注:mockHttpContext.Requestは、mockRequestの内部がスタブアウトされる前に、 mockRequestを返すためにスタブ化されます。この注文が必要だと思います。

// 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
...
于 2008-08-29T01:53:09.167 に答える
10

この手順は、MVC2 で少し変更されたようです (私は RC1 を使用しています)。アクションに特定のメソッドが必要な場合、Phil Haack のソリューションは機能しません ( [HttpPost][HttpGet])。Reflector で調べてみると、これらの属性を確認する方法が変更されたようです。MVC は、 、 、および の値をチェックするrequest.Headersようrequest.Formになりrequest.QueryStringましたX-HTTP-Method-Override

これらのプロパティにモックを追加すると、次のように機能します。

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);
于 2009-12-24T17:15:35.903 に答える
6

または、Typemock Isolator を使用して、偽のコントローラーをまったく送信する必要なく、これを行うことができます。

Isolate.WhenCalled(()=>HttpContext.Request.HttpMethod).WillReturn("Get");
于 2009-01-29T14:29:07.287 に答える
2

私はこの仕様で終わった

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()
    {
    }
} 

そしてジュースはこちら

[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));
    }
}

楽しい

于 2008-10-20T22:04:51.953 に答える
0

長いモッキング手順は摩擦が多すぎると思います。

実際のプロジェクトで ASP.NET MVC を使用して見つけた最善の方法は、単純に通過する IWebContext インターフェイスに HttpContext を抽象化することです。次に、IWebContext を問題なくモックできます。

ここに例があります

于 2008-08-28T23:01:25.523 に答える