Created
May 20, 2014 13:11
-
-
Save danbarua/f450a89f33c92d11e412 to your computer and use it in GitHub Desktop.
Testing FluentValidators with Nancy (appdomain scanning bypassed)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
namespace Nancy.Validation.FluentValidation.Tests | |
{ | |
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
using Nancy.Bootstrapper; | |
using Nancy.ModelBinding; | |
using Nancy.Testing; | |
using Nancy.TinyIoc; | |
using Xunit; | |
using global::FluentValidation; | |
public interface IFooQueryHandler | |
{ | |
bool Exists(string fooName); | |
} | |
public class FakeQueryHandler : IFooQueryHandler | |
{ | |
public bool Exists(string fooName) | |
{ | |
return true; | |
} | |
} | |
public class CreateFoo | |
{ | |
public string Name { get; set; } | |
} | |
public class CreateBar | |
{ | |
public string Name { get; set; } | |
} | |
public class ValidatorWithDependency : AbstractValidator<CreateFoo> | |
{ | |
public ValidatorWithDependency(IFooQueryHandler query) | |
{ | |
this.RuleFor(x => x.Name).Must((req, name) => !query.Exists(name)).WithMessage("Philip says this is a code smell but I don't care."); | |
} | |
} | |
public class ValidatorWithNoDependency : AbstractValidator<CreateBar> | |
{ | |
public ValidatorWithNoDependency() | |
{ | |
this.RuleFor(x => x.Name).NotEmpty().NotNull(); | |
} | |
} | |
public class DummyModule : NancyModule | |
{ | |
public DummyModule() | |
{ | |
Post["/create/bar"] = _ => | |
{ | |
var model = this.BindAndValidate<CreateBar>(); | |
return !this.ModelValidationResult.IsValid ? 400 : 200; | |
}; | |
Post["/create/foo"] = _ => | |
{ | |
var model = this.BindAndValidate<CreateFoo>(); | |
return !this.ModelValidationResult.IsValid ? 400 : 200; | |
}; | |
} | |
} | |
public class TestBootstrapper : ConfigurableBootstrapper | |
{ | |
public TestBootstrapper(Action<ConfigurableBootstrapperConfigurator> configuration) | |
: base(configuration) | |
{ | |
} | |
protected override IEnumerable<Type> ApplicationRegistrationTasks | |
{ | |
get | |
{ | |
//remove the default FluentValidationRegistrations | |
var tasks = base.ApplicationRegistrationTasks.Where(x => x != typeof(FluentValidation.Registrations)); | |
return tasks; | |
} | |
} | |
public class CustomFluentRegistrations : ApplicationRegistrations | |
{ | |
//this will get picked up by the appdomain scanner | |
public CustomFluentRegistrations() | |
{ | |
this.Register<IModelValidator>(typeof(FluentValidationValidator)); | |
this.Register<IFluentAdapterFactory>(typeof(DefaultFluentAdapterFactory)); | |
this.RegisterAll<IFluentAdapter>(); | |
this.Register<IModelValidatorFactory>(typeof(CustomFluentValidationValidatorFactory)); | |
} | |
} | |
//fallback factory will pull validators out of the container | |
public class CustomFluentValidationValidatorFactory : IModelValidatorFactory | |
{ | |
private readonly IFluentAdapterFactory adapterFactory; | |
private readonly TinyIoCContainer container; | |
public CustomFluentValidationValidatorFactory(IFluentAdapterFactory adapterFactory, TinyIoc.TinyIoCContainer container) | |
{ | |
this.adapterFactory = adapterFactory; | |
this.container = container; | |
} | |
public IModelValidator Create(Type type) | |
{ | |
var instance = | |
GetValidatorInstance(type); | |
return (instance != null) ? | |
new FluentValidationValidator(instance, this.adapterFactory, type) : | |
null; | |
} | |
private IValidator GetValidatorInstance(Type type) | |
{ | |
var fullType = | |
CreateValidatorType(type); | |
return (IValidator)container.Resolve(fullType); | |
} | |
private static Type CreateValidatorType(Type type) | |
{ | |
return typeof(AbstractValidator<>).MakeGenericType(type); | |
} | |
} | |
} | |
public class ValidatorWithDependencyTests | |
{ | |
[Fact] | |
public void Should_throw_a_wobbly_if_i_forget_to_register_a_validator() | |
{ | |
// arrange | |
var bootstrapper = new TestBootstrapper( | |
with => | |
{ | |
with.Module<DummyModule>(); | |
}); | |
var browser = new Browser(bootstrapper); | |
// act | |
var ex = Record.Exception( | |
() => browser.Post( | |
"create/bar", | |
with => | |
{ | |
with.HttpRequest(); | |
with.FormValue("Name", string.Empty); | |
})); | |
// assert | |
Assert.NotNull(ex); | |
Assert.True(ex.Message.StartsWith("ConfigurableBootstrapper Exception")); | |
} | |
[Fact] | |
public void Should_be_able_to_test_validators_registered_as_dependencies() | |
{ | |
// arrange | |
var bootstrapper = new TestBootstrapper( | |
with => | |
{ | |
with.Module<DummyModule>(); | |
with.Dependencies(new ValidatorWithNoDependency()); | |
}); | |
var browser = new Browser(bootstrapper); | |
// act | |
var response = browser.Post( | |
"create/bar", | |
with => | |
{ | |
with.HttpRequest(); | |
with.FormValue("Name", string.Empty); | |
}); | |
//assert | |
Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode); | |
} | |
[Fact] | |
public void should_be_able_to_test_validators_with_instance_dependencies() | |
{ | |
var bootstrapper = new TestBootstrapper( | |
with => | |
{ | |
with.Module<DummyModule>(); | |
//Yuck! ConfigurableBootstrapper needs a change to allow registering a class as its base(generic) class | |
with.Dependencies<AbstractValidator<CreateFoo>>(new ValidatorWithDependency(new FakeQueryHandler())); | |
}); | |
var browser = new Browser(bootstrapper); | |
var response = browser.Post( | |
"create/foo", | |
with => | |
{ | |
with.HttpRequest(); | |
with.FormValue("Name", "Test Name"); | |
}); | |
Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment