3

在我的 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);
        }
    }
}
4

1 回答 1

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

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

于 2012-09-25T16:51:15.300 回答