你如何设置ApiController.User

时间:2012-09-25 16:22:46

标签: c# asp.net-mvc unit-testing asp.net-mvc-4 asp.net-web-api

在我的apicontroller中,我使用base.user来识别要在查找中使用的经过身份验证的用户。现在我正在为此编写单元测试,但我无法弄清楚如何模拟apicontroller.user。我是否需要创建请求并将用户设置在那里?或者是否有另一种方法来设置controller.user?

这是我的控制器;我已经模拟了存储库和会员服务。

[Authorize]
public class DocumentController : ApiController
{
    DocumentRepository _repository;
    IStaticMembershipService _membership;

    public IEnumerable<Document> GetDocuments()
    {
        MembershipUser userAccount = _membership.GetUser(base.User);
        IEnumerable<Document> docs = null;

        if (userAccount != null)
        {
            docs = _repository.GetDocumentsByUserId(
                (Guid) userAccount.ProviderUserKey);
        }

        return docs;
    }

这是我的单元测试:

[TestClass]
public class DocumentControllerWebService
{
    private DocumentsContext _context;
    private DocumentRepository _repository;
    private DocumentController _controller;
    private FakeMembershipService _membership;
    private TestContext testContextInstance;

    [TestInitialize]
    public void MyTestInitialize()
    {
        // Create a context with a fake data set provider
        _context = new DocumentsContext(new FakeDbSetProvider());
        _repository = new DocumentRepository(_context);
        _membership = new FakeMembershipService();
        _controller = new DocumentController(_repository, _membership);
    }

    public void GetDocumentsTest()
    {
        string userName = "someUser";
        MembershipUser userAccount = _membership.GetUser(userName);
        Guid userId = (Guid) userAccount.ProviderUserKey;
        Guid anotherUserId = Guid.NewGuid();

        // Get some dummy data and insert it into the fake repository
        List<Document> forms = DocumentDummyData.GetListOfDummyData(
            userId, anotherUserId);
        forms.ForEach(f => _repository.InsertDocument(f));

        // I would like to do this but User is readonly
        _controller.User = userName;

        List<Document> docs = _controller.GetDocuments().ToList();
        foreach (Document expected in forms.Where(d => d.UserId == userId))
        {
            Document actual = docs.Where(
                d => d.DocumentID == expected.DocumentID).FirstOrDefault();
            Assert.IsNotNull(actual);
            Assert.AreEqual(expected.DocumentID, actual.DocumentID);
        }
    }
}

1 个答案:

答案 0 :(得分:0)

如果您从http请求中获取用户,那么您将需要查看一种模拟该方法的方法。值得庆幸的是,已经做了很多次。一个好的开始就是阅读本文

http://www.codethinked.com/post/2008/12/04/Using-SystemWebAbstractions-in-Your-WebForms-Apps.aspx

总结我之后做的事情,一个hanselman博客和一些反复试验:

在你的ApiController中将它添加到你的构造函数

HttpContextWrapper = HttpContextFactory.GetHttpContext();

工厂就是这个

public static class HttpContextFactory
{
    [ThreadStatic]
    private static HttpContextBase _mockHttpContext;
    public static void SetHttpContext(HttpContextBase httpContextBase)
    {
        _mockHttpContext = httpContextBase;
    }

    public static HttpContextBase GetHttpContext()
    {
        if (_mockHttpContext != null)
        {
            return _mockHttpContext;
        }

        if (HttpContext.Current != null)
        {
            return new HttpContextWrapper(HttpContext.Current);
        }
        return null;
    }
}

现在你有一个接缝可以插入你的模拟请求,响应,会话等。

HttpContextBase httpContext = HttpMocks.HttpContext();
HttpContextFactory.SetHttpContext(httpContext);

最后,这是一个相当完全模拟的上下文,我使用

public class HttpMocks
{
    public static HttpContextBase HttpContext()
    {
        var context = MockRepository.GenerateMock<HttpContextBase>();
        context.Stub(r => r.Request).Return(HttpRequest());
        context.Stub(r => r.Response).Return(HttpResponse());
        context.Stub(r => r.Session).Return(HttpSession());
        context.Stub(r => r.Server).Return(HttpServer());
        return context;
    }

    private static HttpServerUtilityBase HttpServer()
    {
        var httpServer = MockRepository.GenerateMock<HttpServerUtilityBase>();
        httpServer.Stub(r => r.MapPath("")).IgnoreArguments().Return("");
        return httpServer;
    }

    private static HttpResponseBase HttpResponse()
    {
        var httpResponse = MockRepository.GenerateMock<HttpResponseBase>();
        var cookies = new HttpCookieCollection {new HttpCookie("UserContext")};
        httpResponse.Stub(r => r.Cookies).Return(cookies);

        Func<string, string> returnWhatWasPassed = x => x;
        httpResponse.Stub(r => r.ApplyAppPathModifier(""))
            .IgnoreArguments().Do(returnWhatWasPassed);

        return httpResponse;
    }

    public static HttpRequestBase HttpRequest()
    {
        var httpRequest = MockRepository.GenerateMock<HttpRequestBase>();
        var cookies = new HttpCookieCollection
        {
            new HttpCookie("UserContext")
        };
        httpRequest.Stub(r => r.Cookies).Return(cookies);

        var parameters = new NameValueCollection
        {
            { "id", "277" },
            { "binderId", "277" }
        };
        httpRequest.Stub(r => r.Params).Return(parameters);
        httpRequest.Stub(r => r.ApplicationPath).Return("/");
        httpRequest.Stub(r => r.AppRelativeCurrentExecutionFilePath)
            .Return("~/");
        httpRequest.Stub(r => r.PathInfo).Return("");

        var serverVariables = new NameValueCollection();
        httpRequest.Stub(r => r.ServerVariables).Return(serverVariables);

        return httpRequest;
    }

    public static HttpSessionStateBase HttpSession()
    {
        var s =  new FakeSessionState();
        s["mocking"] = "true";
        return s;
    }
}

这是一个相当长的答案,但如果你需要更多关于任何事情的详细信息,请告诉我们,你现在可以忽略虚假会话。