最小起订量单元 C# .NET 基本 CRUD 控制器路由测试

本文关键字:CRUD 基本 控制器 路由 测试 NET 单元 | 更新日期: 2023-09-27 17:55:09

我正在尝试为我的 CRUD 路由控制器设置基本的最小起订量测试。我们的应用程序相当小,我们希望先建立基本测试,然后再进行更高级的测试(使用假货和其他什么)。

这是我当前的测试页面:

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

在这里,您将能够看到我正在尝试点击并创建注释的控制器方法。

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

我知道为了使我的创建方法起作用,我需要为该方法提供管理员密钥和管理员名称。我不想为任何这些测试访问数据库,我已经读到这实际上是可能的,我没有很多经验,想知道是否有人可以在这个过程中指导我什么是最好的方法解决这个问题并提供这些信息。

感谢所有的帮助,我希望在这个问题之后,我可以在单元测试中做得更好。

最小起订量单元 C# .NET 基本 CRUD 控制器路由测试

我相信

您要实现的是获得有关围绕创建操作编写单元测试的一些方向。而且您不想访问数据库。您还希望这很简单,并且不想使用高级假货。

你可以在这里写一些测试。以下是您可能想要考虑的一些场景。一个。是否调用 adminNoteService 上的 AdminService.Insert 方法。

二.是否使用预期参数调用 AdminService.Insert 方法

c. 重定向到操作方法返回预期的结果类型。

d.当抛出异常时,是否抛出了具有正确消息、异常类型等的例外。

e.e. 在模型状态有效时验证某些调用。

您可以编写的测试很少,但下面是一个帮助您入门的示例。

我要做的第一件事是非常清楚你想进行单元测试的内容。在测试方法名称中表达此内容的方式。假设我们想定位"c"

而不是像"创建OneNote"这样的测试方法,我更喜欢如下所示的测试方法名称。

公共无效 CreateAction_ModelStateIsValid_EnsureRedirectToActionContainsExpectedResult()

我会对您的 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);
    }
}

正如你所注意到的一个。我不使用实际的系统日期时间,而是使用日期时间委托。这允许我提供一个虚假的日期时间在测试期间。在实际生产代码中,它将使用实际系统日期时间。

二.而不是使用HttpContext.Current.。您可以使用 ControllerContext.HttpContext.User.Identity。这将允许您存根我们的 HttpConext 和 ControllerContext,然后是用户和身份。请参阅下面的测试。

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

如果您熟悉高级单元测试概念(如自动模拟),则此测试可以简化很多。但就目前而言,我相信这会为你指明正确的方向。