Last active
August 29, 2015 14:01
-
-
Save danbarua/9cdf1601b678081aeef0 to your computer and use it in GitHub Desktop.
Testing in Nancy
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
public class CreateUserValidator : AbstractValidator<CreateUser> | |
{ | |
public CreateUserValidator(IUserRepository repository) | |
{ | |
this.RuleFor(x => x.UserName) | |
.NotEmpty() | |
.Length(1, 255); | |
this.RuleFor(x => x.UserName) | |
.Must(x => x != null && !x.Any(char.IsWhiteSpace)) | |
.When(x => x.UserName != null) | |
.WithMessage("'User Name' must not contain whitespace."); | |
this.RuleFor(x => x.UserName) | |
.Must((req, username) => repository.FindByUserName(username) == null) | |
.When(x => x.UserName != null) | |
.WithMessage("That User Name is already taken."); | |
this.RuleFor(x => x.Password).NotEmpty().Length(1, 25); | |
this.RuleFor(x => x.ConfirmPassword).NotEmpty().Length(1, 25); | |
this.RuleFor(x => x.ConfirmPassword).Equal(x => x.Password) | |
.WithMessage("'Confirm Password' should match 'Password'."); | |
this.RuleFor(x => x.Permissions).NotEmpty(); | |
} | |
} | |
[Fact] | |
public void POST_should_validate_the_username_is_not_taken() | |
{ | |
//Given | |
var auditLogger = A.Fake<IAuditLogWriter>(); | |
var repository = A.Fake<IUserRepository>(); | |
A.CallTo(() => repository.FindByUserName("NewUser")).Returns(new User("NewUser","password", new string[0])); | |
var bootstrapper = new TestBootstrapper(with => | |
{ | |
with.Module<UserModule>(); | |
with.Dependencies(repository, auditLogger); //validator gets wired up automagically | |
with.Permission(Permission.CreateUsers); | |
}); | |
var browser = new Browser(bootstrapper); | |
// When | |
var response = browser.Post("/users/create", with => | |
{ | |
with.HttpRequest(); | |
with.FormValue("Username", "NewUser"); | |
with.FormValue("Password", "password1"); | |
with.FormValue("ConfirmPassword", "password1"); | |
with.FormValue("Permissions", "CreateUsers"); | |
}); | |
//Then | |
// it should return the view | |
response.GetViewName().Should().Be("Create"); | |
// it should have the appropriate error messages | |
response.GetPageErrors().Should().Contain(x => x.MemberNames.First() == "UserName" && x.ErrorMessage == "That User Name is already taken."); | |
// it should not save anything | |
A.CallTo(() => repository.Save(A<User>._)).MustNotHaveHappened(); | |
} | |
public class TestBootstrapper : ConfigurableBootstrapper | |
{ | |
public TestBootstrapper(Action<ConfigurableBootstrapperConfigurator> with) | |
: base(innerConfig => | |
{ | |
ApplyConfiguration(innerConfig); | |
with(innerConfig); | |
}) | |
{ | |
this.WithSession(); | |
} | |
protected override void ConfigureConventions(NancyConventions nancyConventions) | |
{ | |
nancyConventions.ViewLocationConventions.Insert(0, (viewName, model, context) => string.Concat(context.ModuleName, "/Views/", viewName)); | |
base.ConfigureConventions(nancyConventions); | |
} | |
private static void ApplyConfiguration(ConfigurableBootstrapperConfigurator config) | |
{ | |
config.ViewFactory<TestingViewFactory>(); | |
} | |
protected override System.Collections.Generic.IEnumerable<Type> ModelValidatorFactories | |
{ | |
get | |
{ | |
//at some point i will override this to not scan my appdomain | |
return base.ModelValidatorFactories; | |
} | |
} | |
} | |
//now in a completely unrelated test... | |
/* | |
System.Exception | |
ConfigurableBootstrapper Exception | |
at Nancy.NancyEngineExtensions.HandleRequest(INancyEngine nancyEngine, Request request, Func`2 preRequest) | |
at Nancy.Testing.Browser.HandleRequest(String method, Url url, Action`1 browserContext) | |
at Nancy.Testing.Browser.HandleRequest(String method, String path, Action`1 browserContext) | |
at NATS.Replay.Management.Tests.Modules.AuditTests.Downloading_the_Audit_log_report.GET_should_be_able_to_specify_the_end_date() in AuditTests.cs: line 438 | |
Nancy.RequestExecutionException | |
Oh noes! | |
at Nancy.NancyEngine.InvokeOnErrorHook(NancyContext context, ErrorPipeline pipeline, Exception ex) | |
Nancy.TinyIoc.TinyIoCResolutionException | |
Unable to resolve type: NATS.Replay.Management.User.ViewModel.CreateUserValidator | |
at Nancy.TinyIoc.TinyIoCContainer.ConstructType(Type requestedType, Type implementationType, ConstructorInfo constructor, NamedParameterOverloads parameters, ResolveOptions options) | |
at Nancy.TinyIoc.TinyIoCContainer.SingletonFactory.GetObject(Type requestedType, TinyIoCContainer container, NamedParameterOverloads parameters, ResolveOptions options) | |
at Nancy.TinyIoc.TinyIoCContainer.ResolveInternal(TypeRegistration registration, NamedParameterOverloads parameters, ResolveOptions options) | |
at System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext() | |
at System.Linq.Enumerable.<CastIterator>d__b1`1.MoveNext() | |
at System.Linq.Enumerable.SingleOrDefault(IEnumerable`1 source, Func`2 predicate) | |
at Nancy.Validation.FluentValidation.FluentValidationValidatorFactory.Create(Type type) | |
at System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext() | |
at System.Linq.Enumerable.WhereEnumerableIterator`1.MoveNext() | |
at System.Linq.Buffer`1..ctor(IEnumerable`1 source) | |
at System.Linq.Enumerable.ToArray(IEnumerable`1 source) | |
at Nancy.Validation.DefaultValidatorLocator.CreateValidator(Type type) | |
at System.Collections.Concurrent.ConcurrentDictionary`2.GetOrAdd(TKey key, Func`2 valueFactory) | |
at Nancy.Validation.DefaultValidatorLocator.GetValidatorForType(Type type) | |
at Nancy.Validation.ModuleExtensions.Validate(INancyModule module, T instance) | |
at Nancy.ModelBinding.ModuleExtensions.BindAndValidate(INancyModule module) | |
at NATS.Replay.Management.Audit.AuditModule.<>c__DisplayClass5.<.ctor>b__2(Object _) in AuditModule.cs: line 51 | |
at CallSite.Target(Closure, CallSite, Func`2, Object) | |
at Nancy.Routing.Route.<>c__DisplayClass4.<Wrap>b__3(Object parameters, CancellationToken context) | |
Nancy.TinyIoc.TinyIoCResolutionException | |
Unable to resolve type: NATS.Replay.Management.User.Model.IUserRepository | |
at Nancy.TinyIoc.TinyIoCContainer.ResolveInternal(TypeRegistration registration, NamedParameterOverloads parameters, ResolveOptions options) | |
at Nancy.TinyIoc.TinyIoCContainer.ConstructType(Type requestedType, Type implementationType, ConstructorInfo constructor, NamedParameterOverloads parameters, ResolveOptions options) | |
*/ | |
[Fact] | |
public void GET_should_be_able_to_specify_the_end_date() | |
{ | |
//Given | |
var auditLogger = new AuditLogReader(dbConnectionFactory); | |
var bootstrapper = new TestBootstrapper(with => | |
{ | |
with.Module<AuditModule>(); | |
with.Dependencies(auditLogger); | |
with.Permission(Permission.GetAuditTrailReport); | |
}); | |
var browser = new Browser(bootstrapper); | |
var response = browser.Get( | |
"/audit/export.csv", | |
with => | |
{ | |
with.Header("Accept", "text/csv"); | |
with.HttpRequest(); | |
with.Query("EndTime", "1959-1-2"); | |
}); | |
response.StatusCode.Should().Be(HttpStatusCode.OK); | |
response.ContentType.Should().Be("text/csv"); | |
var csv = response.Body.AsString(); | |
Assert.False(string.IsNullOrEmpty(csv)); | |
var split = csv.Split(new[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries); | |
split.Count().Should().Be(3); //first line is header | |
var dataToCsv = auditData.Take(2).ToCsv(); | |
csv.Should().BeEquivalentTo(dataToCsv); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment