简体   繁体   English

C#.NET基本CRUD控制器路由的MOQ单元测试

[英]MOQ unit Testing for C# .NET basic CRUD Controller Routing

I am trying to set basic MOQ testing for my CRUD routes controller. 我正在尝试为我的CRUD路由控制器设置基本的起订量测试。 Our application is fairly small and we want to establish basic testing first before we move into more advance testing (using fakes and what not). 我们的应用程序非常小,我们希望先进行基本测试,然后再进行更高级的测试(使用假冒产品或其他)。

This is my current test page: 这是我当前的测试页面:

    [TestClass()]
    public class AdminNotesTest
    {

        [TestMethod]
        public void CreatingOneNote()
        {
            var request = new Mock<HttpRequestBase>();
            request.Setup(r => r.HttpMethod).Returns("POST");
            var mockHttpContext = new Mock<HttpContextBase>();
            mockHttpContext.Setup(c => c.Request).Returns(request.Object);
            var controllerContext = new ControllerContext(mockHttpContext.Object, new RouteData(), new Mock<ControllerBase>().Object);

            var adminNoteController = new AdminNotesController();
            adminNoteController.ControllerContext = controllerContext;
            var result = adminNoteController.Create("89df3f2a-0c65-4552-906a-08bceabb1198");

            Assert.IsNotNull(result);
        }
        [TestMethod]
        public void DeletingNote()
        {
            var controller = new AdminNotesController();
        }
    }
}

Here you will be able to see my controller method I am trying to hit and create a note. 在这里,您将能够看到我尝试点击并创建注释的控制器方法。

[HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult Create(AdminNote adminNote)
        {
            try
            {
                if (ModelState.IsValid)
                {
                    adminNote.AdminKey = System.Web.HttpContext.Current.User.Identity.GetUserId();
                    adminNote.AdminName = System.Web.HttpContext.Current.User.Identity.GetUserName();
                    adminNote.CreateDate = DateTime.Now;
                    adminNote.ModifiedDate = DateTime.Now;

                    adminNote.ObjectState = ObjectState.Added;
                    _adminNoteService.Insert(adminNote);



                    return RedirectToAction("UserDetails", "Admin", new { UserKey = adminNote.UserKey });
                }
            }
            catch (Exception ex)
            {
                ControllerConstants.HandleException(ex);
                ViewBag.PopupMessage(string.Format("We're sorry but an error occurred. {0}", ex.Message));
            }

            return View(adminNote);
        } 

I know that in order for my create method to work I will need to provide the method with a AdminKey and an AdminName. 我知道,为了使我的create方法起作用,我需要为该方法提供AdminKey和AdminName。 I dont want to hit the database for any of these tests and I have read that this is actually possible I dont have a lot of experience and was wondering if someone could guide me in this process as to what would be the best way to approach this and provide this info. 我不想为这些测试中的任何一个打数据库,而我已经读到这实际上是可能的,因为我没有很多经验,并且想知道是否有人可以指导我进行此过程的最佳方法并提供此信息。

Thanks for all the help guys and I do hope that after this question I can get better at unit testing. 感谢所有帮助人员,我希望在提出这个问题后,我能够在单元测试方面做得更好。

I believe what you trying to achieve is to get some direction on writing a Unit Test around Create Action. 我相信您要实现的目标是在编写有关“创建动作”的单元测试时获得一些指导。 And you don't want to hit the database. 而且您不想访问数据库。 You also want this to be simple and don't want to use advanced Fakes. 您还希望这很简单,并且不想使用高级的伪造品。

There are few tests you may write here. 您可以在此处编写一些测试。 Below are some scenarios you may want to think. 以下是您可能需要考虑的一些方案。 a. 一种。 Whether the AdminService.Insert Method on the adminNoteService is called. 是否调用adminNoteService上的AdminService.Insert方法。

b. b。 Whether the AdminService.Insert method called with expected parameters AdminService.Insert方法是否使用预期参数调用

c. C。 RedirectToAction method return the expected type of result. RedirectToAction方法返回预期的结果类型。

d. d。 When an exception being thrown whether the exeception has been thrown with correct message, exception type etc. 当引发异常时,是否已经使用正确的消息,异常类型等引发了感知。

e. e。 Verify certain calls when the Model state is valid. 当“模型”状态有效时,请验证某些调用。

There are few tests you can write, but below is an example to get you started. 您可以编写很少的测试,但是下面是一个入门的示例。

First thing I would do is to be very clear on what you trying to Unit Test. 我要做的第一件事是非常清楚您要进行单元测试的内容。 The way you express this in your test method name. 在测试方法名称中表达此内容的方式。 Let's say we want to target the 'c' 假设我们要定位“ c”

Instead of a test method like "CreatingOneNote" I would prefer a test method name like below.. 而不是像“ CreatingOneNote”这样的测试方法,我更喜欢下面的测试方法名称。

public void CreateAction_ModelStateIsValid_EnsureRedirectToActionContainsExpectedResult() 公共无效CreateAction_ModelStateIsValid_EnsureRedirectToActionContainsExpectedResult()

I would make the following changes to your SUT/Controller (System Under Test) 我将对您的SUT /控制器(被测系统)进行以下更改

public class AdminsNotesController : Controller
{
    private readonly IAdminNoteService _adminNoteService;

    public AdminsNotesController(IAdminNoteService adminNoteService)
    {
        _adminNoteService = adminNoteService;
        FakeDateTimeDelegate = () => DateTime.Now;
    }

    public Func<DateTime> DateTimeDelegate { get; set; }

    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult Create(AdminNote adminNote)
    {
        try
        {
            if (ModelState.IsValid)
            {
                adminNote.AdminKey = this.ControllerContext.HttpContext
                .User.Identity.GetUserId();
                adminNote.AdminName = this.ControllerContext.HttpContext
                .User.Identity.GetUserName();
                adminNote.CreateDate = DateTimeDelegate();
                adminNote.ModifiedDate = DateTimeDelegate();

                adminNote.ObjectState = ObjectState.Added;
                _adminNoteService.Insert(adminNote);

                return RedirectToAction("UserDetails", "Admin", 
                new { UserKey = adminNote.UserKey });
            }
        }
        catch (Exception ex)
        {
            ControllerConstants.HandleException(ex);
            ViewBag.PopupMessage(string.Format
            ("We're sorry but an error occurred. {0}", ex.Message));
        }

        return View(adminNote);
    }
}

As you have noticed a. 如您所知a。 I don't use the real system date time, instead I use DateTime Delegate. 我不使用实际的系统日期时间,而是使用DateTime委托。 This allows me to provide a fake date time during testing. 这使我可以在测试期间提供假的日期时间。 In the real production code it will use real system date time. 在实际生产代码中,它将使用实际系统日期时间。

b. b。 Instead of useing HttpContext.Current.. you can use ControllerContext.HttpContext.User.Identity. 代替使用HttpContext.Current ..,可以使用ControllerContext.HttpContext.User.Identity。 This will allow you to stub our the HttpConext and ControllerContext then User and Identity. 这将允许您先对HttpConext和ControllerContext进行存根,然后再对User和Identity进行存根。 Please see the test below. 请参阅下面的测试。

[TestClass]
public class AdminNotesControllerTests
{
    [TestMethod]
    public void CreateAction_ModelStateIsValid_EnsureRedirectToActionContainsExpectedRoutes()
    {
        // Arrange
        var fakeNote = new AdminNote();
        var stubService = new Mock<IAdminNoteService>();
        var sut = new AdminsNotesController(stubService.Object);

        var fakeHttpContext = new Mock<HttpContextBase>();
        var fakeIdentity = new GenericIdentity("User");
        var principal = new GenericPrincipal(fakeIdentity, null);

        fakeHttpContext.Setup(t => t.User).Returns(principal);
        var controllerContext = new Mock<ControllerContext>();
        controllerContext.Setup(t => t.HttpContext)
        .Returns(fakeHttpContext.Object);
        sut.ControllerContext = controllerContext.Object;
        sut.FakeDateTimeDelegate = () => new DateTime(2015, 01, 01);

        // Act
        var result = sut.Create(fakeNote) as RedirectToRouteResult;

        // Assert
        Assert.AreEqual(result.RouteValues["controller"], "Admin");
        Assert.AreEqual(result.RouteValues["action"], "UserDetails");
    }       
}

This test can be simplify a lot if you are familiar advanced Unit Testing concepts such as AutoMocking . 如果您熟悉诸如AutoMocking之类的高级单元测试概念,则可以大大简化此测试。 But for the time being, I'm sure this will point you to the right direction. 但是暂时,我相信这将为您指明正确的方向。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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