简体   繁体   中英

Unit-test simple-membership provider?

How to unit-test a controller, which uses Simple Membership provider?

Controller takes MyViewModel object as input & inserts it into DB. When operation completes successfully user is redirected to Dashboard.

Controller is having WebSecurity as dependency. So when unit-testing I get parameter null exception for HttpContext, in following line

userLakshya.UserId = WebSecurity.HasUserId ? WebSecurity.CurrentUserId : -1;

How do I pass HttpContext parameter to the controller?

Code listing:

    [HttpPost]
    public ActionResult Create(MyViewModel myVM)
    {
        MyModel myModel = myVM.Model;
        if (ModelState.IsValid)
        {
            userLakshya.UserId = WebSecurity.HasUserId ? WebSecurity.CurrentUserId : -1;
            db.MyModels.Add(myModel);
            db.SaveChanges();
            return RedirectToAction("Dashboard");
        }
        return View(myVM);
    }

    [TestMethod]
    public void TestLoginAndRedirectionToDashboard()
    {
        MyController cntlr = new MyController();
        var ret = ulCntlr.Create(new MyViewModel(){
            //Initialize few properties to test
        });
        /*
         * Controller throws parameter null exception for HttpContext
         * => Issue: Should I pass this? since the controller uses WebSecurity inside
         * */
        ViewResult vResult = ret as ViewResult;
        if (vResult != null)
        {
            Assert.IsInstanceOfType(vResult.Model, typeof(UserLakshya));
            UserLakshya model = vResult.Model as UserLakshya;

            if (model != null)
            {
                //Assert few properties from the return type.
            }
        }
    }  

The problem you have is that your Create method is violating the Dependency Inversion Principle ie your method should "Depend upon Abstractions. Do not depend upon concretions".

You should refactor your code so that instead of using the WebSecurity class directly, you instead use an abstraction eg you could create an ISecurity interface. Your concrete version of ISecurity (eg Security) could then contain the reference to WebSecurity, hence removing the direct dependency.

(You have already done this for your database dependency (ie your db member), you just need to do this for the Security aspect of your code.)

eg

public Interface ISecurity
{
 int GetUserId();
}

Then instead of:

userLakshya.UserId = WebSecurity.HasUserId ? WebSecurity.CurrentUserId : -1;

you could use:

userLakshya.UserId = security.GetUserId();

Then to test the "Create" controller you could mock the behavior of ISecurity (indeed I'd also recommend mocking the behaviour of your "db" object) using a mocking framework (eg Moq ). An example of mocking with Moq code is:

var mock = new Mock<ISecurity>();
mock.Setup(security=> security.GetUserId()).Returns("ATestUser");

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM