MVC,FluentValidation和Ninject的单元测试接线

时间:2013-02-26 16:07:33

标签: asp.net-mvc ninject fluentvalidation

我使用Ninject.Extensions.Mvc.FluentValidation包使用FluentValidation和Ninject建立了一个MVC Web项目。我直接跟踪了该软件包的文档。

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

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

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

2 个答案:

答案 0 :(得分:2)

我有类似的设置,但我使用Unity代替Ninject。

我的IoC容器继承了UnityContainer,我在其中注册了所有的repos,validarots等。我受益于此,因为我有验证器具有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 :(得分: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进行测试。

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