【问题标题】:Unit test wiring of MVC, FluentValidation, and NinjectMVC、FluentValidation 和 Ninject 的单元测试接线
【发布时间】:2013-03-07 06:36:08
【问题描述】:

我已经使用 Ninject.Extensions.Mvc.FluentValidation 包设置了一个带有 FluentValidation 和 Ninject 的 MVC Web 项目。我直接按照那个包的文档。

我想编写一个自动化测试来验证此接线,并检查模型验证是否将按预期使用 FluentValidation 验证器。为了做到这一点,我很难在测试中启动 MVC 应用程序的正确部分。

基本上,我想启动 MVC 应用程序,以便创建 Ninject 内核、连接模型绑定器并创建验证器。然后我想尝试通过 MVC 模型验证来验证实体,并确保显示来自验证器的预期消息。

自动化测试 Ninject、MVC 和 FluentValidation 之间交互的最佳方法是什么?

【问题讨论】:

  • 当您需要验证组件交互时,您需要进行集成测试。
  • 是的,很好。集成测试。我不是在讨论测试术语,而是在寻找如何解决这个特定的测试用例。

标签: asp.net-mvc ninject fluentvalidation


【解决方案1】:

我有类似的设置,但我使用 Unity 而不是 Ninject。

我的 IoC 容器继承了 UnityContainer,我在其中注册了我的所有 repos、validarot 等。我从中受益,因为我有具有 repo 依赖项的验证器(例如,UserRegistrationValidator 检查唯一用户名)。

我的 IoC 容器也实现了IValidatorFactory。我使用它注册一个全局 ModelValidatorProvider ,如下所示:

var ioc = new IoCContainer();
ModelValidatorProviders.Providers.Add(new FluentValidationModelValidatorProvider(ioc));
DataAnnotationsModelValidatorProvider.AddImplicitRequiredAttributeForValueTypes = false;

通过此设置,我知道我的验证器将拦截控制器操作中的模型验证,但前提是验证器由 ValidatorFactory 解析。

所以基本上我有两组测试

- IoC 测试

通过这些我测试我的 IoC 容器是否可以解析模型的验证器。使用 Unity,它看起来像这样:

// Arrange
var ioc = new IoCContainer();

// Assert
Assert.IsTrue(ioc.IsRegistered(IValidator<MyModel>));

如果您的所有模型都在一个命名空间下,您甚至可以编写一个单元测试,方法是从特定命名空间获取所有类型并检查 IValidator 是否在循环中为它们注册。

- 验证器测试

这些是测试我的(视图)模型的常见测试:

// Arrange
var validator = new MyModelValidator();
var model = new MyModel{ Name = null };

// Assert
validator.ShouldHaveValidationErrorFor(x => x.Name, model)

这样就不需要旋转应用程序,您只需测试您创建的内容。

希望这会有所帮助。

【讨论】:

  • +1 最好将它分解成这样的单元测试,而不是进行基于浏览器的集成测试(尽管其中有一些地方)。
  • 完全同意这种测试方法。所以是的,您测试容器以确保其正常工作,并测试验证器以确保它们正常工作。我有那些测试。我要做的是编写一个测试,以确保 将验证器工厂连接到 MVC 工作正常。也许您描述的所有其他测试都没有必要。但我想看看这是否可能。
  • 嗯,测试 wiring 本身需要启动所有 MVC 基础架构,因此这基本上意味着通过应用程序的 UI 进行测试。对静态类的调用涉及连接自定义验证并测试 您需要某种包装器。但是话又说回来,很难测试您的包装器是否被调用。我个人认为这是测试您的区域或全局过滤器是否已注册。我需要这种测试吗?我认为不会,因为您会在早期开发阶段注意到任何缺陷
  • 通过 UI 测试接线对我来说会产生误导,因为 UI 可能随时更改,并且当所有接线相同并且很可能完好无损时,这肯定会使这些测试失败。所以 summa summarum 我不会为接线本身编写任何测试......至少在第一次失败之前。那我怎么考?老实说我不知道​​
【解决方案2】:

我们这里使用的集成测试是Selenium Webdriver,你可以用NuGet得到它。我们编写代码使用page pattern,因此更易于维护。

当我想检查是否需要字段或任何其他自定义验证时,我会执行以下操作:

    [TestFixture]
    public class CenterTests : TestBase
    {

        [Test]
        public void CreateViewAndEditShouldWork()
        {   
            S.OpenWithCI();
            var loginPage = new LoginPage(S);
            var homePage = loginPage.LoginValidUser("email", "Password");
            var centerListPage = homePage.ClickCenterAndRoomLink();
            var centerPage = centerListPage.ClickCreateLink();

            //Create
            centerPage.CreateInvalidCenter();
            Assert.That(S.FindElement(By.CssSelector("span[for=Name]")).Text, Is.StringContaining(Strings.Error_Required));
            Assert.That(S.FindElement(By.CssSelector("span[for=EnglishName]")).Text, Is.StringContaining(Strings.Error_Required));

            centerListPage = centerPage.CreateValidCenter("Saguenay", "Sag", "2089 blv Talbot");
            Thread.Sleep(2000); 
            S.ExpectSuccessNotice(Strings.CenterCreatedSuccessfully);
        }
    }

这是我的 TestBase 助手类的代码:

namespace Afi.AutomatedTests.Helpers
{
    [TestFixture]
    public class TestBase
    {
        protected IWebDriver S;

        [SetUp]
        public virtual void TestSetup()
        {
            S = new ChromeDriver();
            S.Manage().Window.Size = new Size(1024, 768);
            S.Manage().Timeouts().ImplicitlyWait(TimeSpan.FromSeconds(10));
        }

        [TearDown]
        public void TearDown()
        {
            S.Quit();
        }

        public string GetUrl(string relativePath)
        {
            if(!relativePath.StartsWith("/"))
                throw new ArgumentException("Relative URL must begins with /");

            return "http://afi.local" + relativePath;
        }
    }
}

所有这些测试都在另一个名为 AutomatedTests 的项目中,我可以像运行单元测试 (resharper/nunit) 一样运行它们。它使用 Chromedriver 进行测试。

如果您需要更多信息,请告诉我。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-01-10
    • 1970-01-01
    • 2013-07-17
    • 1970-01-01
    • 2012-05-12
    • 1970-01-01
    • 2015-02-03
    相关资源
    最近更新 更多