Skip to content

Instantly share code, notes, and snippets.

@danbarua
Last active August 29, 2015 14:01
Show Gist options
  • Save danbarua/9cdf1601b678081aeef0 to your computer and use it in GitHub Desktop.
Save danbarua/9cdf1601b678081aeef0 to your computer and use it in GitHub Desktop.
Testing in Nancy
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