代码之家  ›  专栏  ›  技术社区  ›  szpic

如何单元测试POST方法

  •  2
  • szpic  · 技术社区  · 12 年前

    我对测试后置方法有问题。 在该方法中,AntiForgeryToken被选中,我不知道如何模拟它。 除此之外,一切都有效。

    这里是我要测试的方法:

    [HttpPost]
        //[ValidateAntiForgeryToken]
        public ActionResult Create([Bind(Include="Id,Name,Manufacturer,CatalogNo")] Device device)
        {
            ValidateRequestHeader(Request);
            if (String.IsNullOrWhiteSpace(device.Name)||String.IsNullOrWhiteSpace(device.Manufacturer)||String.IsNullOrWhiteSpace(device.CatalogNo))
            {
                ModelState.AddModelError("", "Niepoprawne dane");
                return PartialView(device);
            }
            unitOfWork.deviceRepository.Insert(device);
            unitOfWork.Save();
            return Json(new { ok = true, newurl = Url.Action("Index") });
        }
    

    我已经嘲笑过:

            private IUnitOfWork fakeRepo;
        DeviceController DC;
        [TestInitialize]
        public void Initialize()
        {
            Mock<IUnitOfWork> mock = new Mock<IUnitOfWork>();
            mock.Setup(m => m.deviceRepository.Get(
                It.IsAny<List<Expression<Func<Device, bool>>>>(),
                It.IsAny<Func<IQueryable<Device>, IOrderedQueryable<Device>>>(),
                null))
                .Returns(new[] { new Device { Id = 1, Manufacturer = "a", Name = "b", CatalogNo = "x" } });
            mock.Setup(m => m.deviceRepository.Get()).Returns(new[] { new Device { Id = 1, Manufacturer = "a", Name = "b", CatalogNo = "z" } });
            fakeRepo = mock.Object;
            DC = new DeviceController(fakeRepo);
        }
    

    但我不知道如何进行测试 AntiforgeryToken 此处代码:

    public void ValidateRequestHeader(HttpRequestBase request)
        {
            string cookieToken = "";
            string formToken = "";
    
            if (request.Headers["RequestVerificationToken"] != null)
            {
                string[] tokens = request.Headers["RequestVerificationToken"].Split(':');
                if (tokens.Length == 2)
                {
                    cookieToken = tokens[0].Trim();
                    formToken = tokens[1].Trim();
                }
            }
            AntiForgery.Validate(cookieToken, formToken);
        }
    

    我不能评论这个呼叫测试的目的,但这个解决方案似乎有点难看。

    你能提出任何修改建议吗?

    1 回复  |  直到 12 年前
        1
  •  3
  •   Sam Leach    12 年前

    看起来你需要嘲笑 HttpRequestBase AntiForgery .

    你怎么嘲笑他们?

    您将它们包装在自己的界面中,以暴露您需要或可能在不久的将来需要的行为。在生产代码中,您提供了真实的.NET实现、测试和模拟。

    MSDN表示 AntiForgery.Validate

    验证来自HTML表单字段的输入数据是否来自用户 谁提交了数据。

    这个 signature that takes two string arguments 回报 void .

    你的模拟 IAntiForgeryValidator 会有一个 Validate(string, string) 同时返回void的方法。

    public interface IAntiForgeryValidator
    {
        void Validate(string cookieToken, string formToken);
    }
    
    public class AntiForgeryValidator : IAntiForgeryValidator
    {
        public void Validate(string cookieToken, string formToken)
        {
            AntiForgery.Validate(cookieToken, formToken);
        }
    }
    

    您可以对void方法使用回调,并验证它们被调用的次数是否正确:

    antiForgeryMock.Setup(m => m.Validate(
            It.IsAny<string>(),
            It.IsAny<string>()))
            .Callback((string cookieToken, string formToken) =>
                                {
                                    // call back
                                });
    
    antiForgeryMock.Verify(m => m.Validate(
            It.IsAny<string>(),
            It.IsAny<string>()), Times.Once());
    

    你还有另一个选择(作弊),那就是将你的电话转接到 ValidateRequestHeader() 在里面 Create() 。这将使您能够测试您的代码的其余部分,但由于真正的 ValidateRequestHeader() 如果不测试方法,可能会在生产代码中造成麻烦。