How to unit test child validators with When() condition with FluentValidation.TestHelper - asp.net-mvc-3

The extension method .ShouldHaveChildValidator() in the FluentValidation.TestHelper namespace doesn't have an overload that takes the model. How do I then test that the child validators are set up correctly when using a When() clause like in the following example?
E.g.
public class ParentModel
{
public bool SomeCheckbox { get; set; }
public ChildModel SomeProperty { get; set; }
}
public class ParentModelValidator : AbstractValidator<ParentModel>
{
RuleFor(m => m.SomeProperty)
.SetValidator(new ChildModelValidator())
.When(m => m.SomeCheckbox);
}
I want to Assert that if SomeCheckbox is true, then the child validator is present, and if SomeCheckbox is false, then the child validator isn't present.
I have the following so far in the unit test:
ParentModelValidator validator = new ParentModelValidator();
validator.ShouldHaveChildValidator(
m => m.SomeProperty,
typeof(ChildModelValidator));
but that doesn't take into account the .When() condition.
I notice other methods in the FluentValidation.TestHelper namespace such as .ShouldHaveValidationErrorFor() have an overload that takes the model, so it's easy to test a simple property type with a When() clause by setting up a model that satisfies the precondition.
Any ideas?

Here's a snippet of how I achieve this:
public class ParentModelSimpleValidator : AbstractValidator<ParentModel>
{
public ParentModelSimpleValidator()
{
When(x => x.HasChild, () =>
RuleFor(x => x.Child)
.SetValidator(new ChildModelSimpleValidator()));
}
}
public class ChildModelSimpleValidator : AbstractValidator<ChildModel>
{
public ChildModelSimpleValidator()
{
RuleFor(x => x.ChildName)
.NotEmpty()
.WithMessage("Whatever");
}
}
Here's the relevant simplified models:
[Validator(typeof(ParentModelSimpleValidator))]
public class ParentModel
{
public bool HasChild { get { return Child != null; } }
public ChildModel Child { get; set; }
}
[Validator(typeof(ChildModelSimpleValidator))]
public class ChildModel
{
public string ChildName { get; set; }
public int? ChildAge { get; set; }
}
Here's a sample unit test:
[TestMethod]
public void ShouldValidateChildIfParentHasChild()
{
var validator = new ParentModelSimpleValidator();
var model = new ParentModel
{
ParentName = "AABBC",
Child = new ChildModel { ChildName = string.Empty }
};
validator.ShouldHaveErrorMessage(model, "Whatever");
}

very late to the game here, but I just started using FluentValidation and that was my solution
public class ParentValidator: AbstractValidator<ParentModel>
{
public ParentValidator()
{
// other rules here
// use == for bool?
When(model => model.SomeBoolProperty == false, () => RuleFor(model => model.ChildClass).SetValidator(new ChildClassValidator()));
}
}
public class ChildClassValidator: AbstractValidator<ChildClass>
{
public ChildClassValidator()
{
this
.RuleFor(model => model.SomeProperty).NotNull();
}
}
then the test is
[TestMethod]
public void ParentValidator_should_have_error_in_child_class_property_when_bool_is_false_on_parent()
{
// Arrange - API does not support typical unit test
var validator = new ParentValidator()
var foo = new ParentModel() { SomeBoolProperty = false };
foo.ChildClass.SomeProperty = null;
// Act
var result = validator.Validate(foo);
// Assert - using FluentAssertions
result.Errors.Should().Contain(err => err.PropertyName == "ChildClass.SomeProperty");
}

Related

Nested validators can only be used with Member Expressions

I am trying to use fluent validation .
Looking to run validation against the IList items.
public class ProgramDetailsValidatorForBulkEdit : ValidatorCollection<IList<ProgramDTO>>
{
public ProgramDetailsValidatorForBulkEdit()
{
RuleFor(x => x).Cascade(CascadeMode.StopOnFirstFailure).SetCollectionValidator(new ProgramDetailsValidator1());
}
}
public class ProgramDetailsValidator1 : AbstractValidator<ProgramDTO>
{
public ProgramDetailsValidator1()
{
RuleFor(c => c.Capacity).NotNull()
.WithMessage(String.Format(AppConstants.ValidationTemplates.RequiredField, "Capacity"));
}
}
The error returned when calling the line is "Nested validators can only be used with Member Expressions."
RuleFor(x => x).Cascade(CascadeMode.StopOnFirstFailure).SetCollectionValidator(new ProgramDetailsValidator1());
Reason of error
Error message contains words "Member Expressions". The problem is in RuleFor(x => x). Nested validators must be used only with lambdas which select some members of x, for example, with x => x.MySubobject1. Lambda x => x does not select any member of x.
To validate the collection
Create object containing the list:
public class MyObject
{
public List<Item> Items { get; set; }
}
You can use generics to create 1 universal object and validator for it for all lists.
public class MyObjectValidator : AbstractValidator<MyObject>
{
public MyObjectValidator()
{
RuleFor(x => x.Items) // will work, because it is not "x => x"
.SetCollectionValidator(new ItemValidator());
}
}
To validate an object
Use lambdas pointing to members to validate inner objects and use inheritance from your object's validator to validate the root x.
public class MySimpleObject { ... }
public class MyCompositeObject : MySimpleObject
{
public MyType1 MySubobject1 { get; set; }
public MyType2 MySubobject2 { get; set; }
}
public class MySimpleObjectValidator : AbstractValidator<MySimpleObject>
{
public MySimpleObjectValidator()
{
...
}
}
public class MyCompositeObjectValidator : MySimpleObjectValidator
{
public MyCompositeObjectValidator () : base() // Call base validator to implement rules for "x => x" written in MySimpleObjectValidator!
{
// Rules for SUBobjects will work
RuleFor(x => x.MySubobject1)
.SetValidator(new MyType1Validator())
.WithName("Subobject1's errors group");
RuleFor(x => x.MySubobject2)
.SetValidator(new MyType2Validator())
.WithName("Subobject2's errors group");
}
}

Web API controller returning boolean

I have a Web API where one of the methods in a controller return true or false when validating user id which is a string of numbers. I do no have an actual database yet, so I sort of mocked up the set of values in the repository.
Below is my code:
My repository class:
public class myRepository
{
public myClasses.Employee[] GetAllEmployees()
{
return new myClasses.Employee[]
{
new myClasses.Employee
{
empId="111111",
empFName = "Jane",
empLName="Doe"
},
new myClasses.Employee
{
empId="222222",
empFName = "John",
empLName="Doe"
}
};
}
public bool VerifyEmployeeId(string id)
{
myClasses.Employee[] emp = new myClasses.Employee[]
{
new myClasses.Employee
{
empId="111111",
empFName = "Jane",
empLName="Doe"
},
new myClasses.Employee
{
empId="222222",
empFName = "John",
empLName="Doe"
}
};
for (var i = 0; i <= emp.Length - 1; i++)
{
if (emp[i].empId == id)
return true;
}
return false;
}
}
and my model class:
public class myClasses
{
public class Employee
{
public string empId { get; set; }
public string empFName { get; set; }
public string empLName { get; set; }
}
}
and here is my controller:
public class myClassesController : ApiController
{
private myRepository empRepository;
public myClassesController()
{
this.empRepository = new myRepository();
}
public myClasses.Employee[] GetEmployees()
{
return empRepository.GetAllEmployees();
}
public bool VerifyEmployee(string id)
{
return empRepository.VerifyEmployeeId(string id);
}
}
Now when i compile it I get an error:
} expected
Type or namespace definition, or end-of-file expected
; expected
in line
return empRepository.VerifyEmployeeId(string id);
of my controller.
My question is using boolean the best way to return Success or Failure from Web API method or is there a better way? and also why am I getting this error. I am new to Web API
The compile error is caused by this;
return empRepository.VerifyEmployeeId(string id);
You should rewrite to:
return empRepository.VerifyEmployeeId(id);
You don't have you specify the type of the argument when calling a function.
About returning true or false; if you intend to only check whether the employee is valid or not, I should leave it this way. If you plan to use that employee data more you could rewrite that function so it returns the actual employee itself, and return 404: Not Found when the Employee is not found for instance.

Why does NHibernate mapping-by-code ignore my Oracle-cased table name:

I am using an Oracle Database with NHibernate 3.3.2.4000.
I have a unit test set up to verify that an entity collection can be selected from the table. Here's what it looks like:
[TestFixture]
public class UnitOfWorkIntegrationTests
{
private IUnitOfWork _unitOfWork;
private INHibernateSessionFactory _nHibernateSessionFactory;
private IActiveSessionManager _activeSessionManager;
[SetUp]
public void BeforeEachTest()
{
_nHibernateSessionFactory = new NHibernateSessionFactory();
_activeSessionManager = new ActiveSessionManager();
_unitOfWork = new UnitOfWork(_nHibernateSessionFactory, _activeSessionManager);
}
[Test]
public void ShouldFetchOAuthMemberships()
{
var oauths = _unitOfWork.OAuthMemberships.ToArray();
oauths.ShouldNotBeNull();
}
}
The line that fetches my OAuthMemberships collection is throwing this exception:
could not execute query
[ select oauthmembe0_.id as id13_ from bckgrd_booklet_app.OAuthMembership oauthmembe0_ ]
[SQL: select oauthmembe0_.id as id13_ from bckgrd_booklet_app.OAuthMembership oauthmembe0_]
My OAuthMembership class and mapping are below. As you can see I am defining the table name as "OAUTH_MEMBERSHIP", but the generated SQL includes the camel-cased class name instead. I have no table name conventions defined. Why does NHibernate ignore my Oracle-cased table names?
public class OAuthMembership
{
public virtual int Id { get; set; }
public virtual string Provider { get; set; }
public virtual string ProviderUserId { get; set; }
public virtual UserProfile UserProfile { get; set; }
}
public class OAuthMembershipMap : ClassMapping<OAuthMembership>
{
public void OAuthMembership()
{
Table("OAUTH_MEMBERSHIP");
Id(x => x.Id, m => m.Column("ID"));
Property(x => x.Provider, m => m.Column("PROVIDER"));
Property(x => x.ProviderUserId, m => m.Column("PROVIDER_USER_ID"));
ManyToOne(x => x.UserProfile, m => m.Column("USER_PROFILE_ID"));
}
}
Here's my NHibernateSessionFactory:
public interface INHibernateSessionFactory
{
ISession Create();
}
public class NHibernateSessionFactory : INHibernateSessionFactory
{
private static readonly ILog Log = LogManager.GetLogger(typeof(NHibernateSessionFactory).Name);
private readonly static ISessionFactory SessionFactory;
public static string ConnectionString
{
get
{
return ConfigurationManager.ConnectionStrings["MyConnection"].Return(x => x.ConnectionString,
"Data Source=myServer;User ID=bckgrd_booklet_app;Password=myPass;");
}
}
static NHibernateSessionFactory()
{
try
{
var mapper = new ModelMapper();
mapper.AddMappings(Assembly.GetExecutingAssembly().GetExportedTypes());
HbmMapping domainMapping = mapper.CompileMappingForAllExplicitlyAddedEntities();
var configure = new NHibernate.Cfg.Configuration().Configure();
configure.AddMapping(domainMapping);
configure.BuildMappings();
configure.DataBaseIntegration(x =>
{
x.Driver<OracleClientDriver>();
x.Dialect<Oracle10gDialect>();
x.ConnectionStringName = ConnectionString;
})
.CurrentSessionContext<WebSessionContext>();
SessionFactory = configure.BuildSessionFactory();
}
catch (Exception ex)
{
Log.Error("NHibernateSessionFactory did not initialize correctly.", ex);
throw;
}
}
public ISession Create()
{
Log.Debug("Creating new session.");
return SessionFactory.OpenSession();
}
}
My ActiveSessionManager:
public interface IActiveSessionManager
{
void ClearActiveSession();
NHibernate.ISession GetActiveSession();
void SetActiveSession(NHibernate.ISession session);
}
public class ActiveSessionManager : IActiveSessionManager
{
[ThreadStatic]
private static ISession _current;
public ISession GetActiveSession()
{
return _current;
}
public void SetActiveSession(ISession session)
{
_current = session;
}
public void ClearActiveSession()
{
_current = null;
}
}
Relevant parts of my UnitOfWork definition:
public interface IUnitOfWork
{
//...
IQueryable<OAuthMembership> OAuthMemberships { get; }
IQueryable<T> All<T>();
//...
}
public class UnitOfWork : IUnitOfWork
{
private readonly ISession _session;
//...
public IQueryable<OAuthMembership> OAuthMemberships
{
get { return All<OAuthMembership>(); }
}
public UnitOfWork(
INHibernateSessionFactory sessionFactory,
IActiveSessionManager activeSessionManager)
{
_session = sessionFactory.Create();
activeSessionManager.SetActiveSession(_session);
}
public IQueryable<T> All<T>()
{
return _session.Query<T>();
}
//...
}
I found my error after adding Fluent NHibernate to my project and making the same error there.
My OAuthMembershipMap doesn't have a constructor. I had mistakenly added a void method called OAuthMembership instead, so my table mapping and my Id and Property mappings failed. See the corrected code:
public class OAuthMembershipMap : ClassMapping<OAuthMembership>
{
public OAuthMembershipMap()
{
Table("OAUTH_MEMBERSHIP");
Id(x => x.Id, m => m.Column("ID"));
Property(x => x.Provider, m => m.Column("PROVIDER"));
Property(x => x.ProviderUserId, m => m.Column("PROVIDER_USER_ID"));
ManyToOne(x => x.UserProfile, m => m.Column("USER_PROFILE_ID"));
}
}

IValidatableObject passes validation but StringLength is Invalid

I have a test class with a couple tests that check to see if the entity IsValid. I moved to using IValidatableObject from having my own custom validation but I'm stuck with the correct validation technique.
This is my Test class:
[TestFixture]
public class StudentTests {
private static Student GetContactWithContactInfo()
{
return new Student(new TestableContactRepository())
{
Phone = "7275551111"
};
}
private static Student GetContactWithoutContactInfo()
{
return new Student(new TestableContactRepository());
}
[Test]
public void Student_Saving_StudentHasInfo_IsValid ()
{
// Arrange
Student student = GetContactWithContactInfo();
// Act
student.Save();
// Assert
Assert.IsTrue(student.IsValid);
}
[Test]
public void Student_Saving_StudentDoesNotHaveInfo_IsNotValid ()
{
// Arrange
Student student = GetContactWithoutContactInfo();
// Act
student.Save();
// Assert
Assert.IsFalse(student.IsValid);
}
}
This is my entity:
public class Student : IValidatableObject
{
private readonly IContactRepository contactRepository;
public Student(IContactRepository _contactRepository)
{
contactRepository = _contactRepository;
Contacts = new List<Student>();
}
[Required]
public int Id { get; private set; }
[StringLength(10, MinimumLength = 10)]
public string Phone { get; set; }
public List<Student> Contacts { get; private set; }
public bool IsValid { get; private set; }
public void Save()
{
if (IsValidForPersistance())
{
IsValid = true;
Id = contactRepository.Save();
}
}
private bool IsValidForPersistance()
{
return Validator.TryValidateObject(this, new ValidationContext(this), null, true);
}
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
if (string.IsNullOrEmpty(Phone) && Contacts.All(c => string.IsNullOrEmpty(c.Phone)))
yield return new ValidationResult("The student or at least one contact must have a phone number entered", new[] { "Phone Number" });
}
}
As you can see the tests test for IsValid by calling the IsValidForPersistance. Validate will eventually have more validation .
The above tests all pass using this method but this test below also passes but should not.
[Test]
public void Student_Saving_HasContactInfoWithInvalidLength_IsNotValid()
{
// Arrange
Contact student = GetContactWithoutContactInfo();
student.Phone = "string";
// Act
student.Save();
// Assert
Assert.IsFalse(student.IsValid);
}
Here I'm setting my own Phone value of an invalid length string. I expect validation to fail because of the StringLength annotation set at min and max 10 characters.
Why is this passing?
Update
There was a problem with the custom validation, updated the code with the change. Along with the suggestion from nemesv about not having a private modifier on the Phone property it now works. I've updated all the code to working.
Validator.TryValidateObject only checks the RequiredAttributes (and also other things like type level attributes and IValidatableObject implementation) by default.
If you need to validate all the attributes like StringLength etc. you need to set the validateAllProperties parameter of the method to true
private bool IsValidForPersistance() {
return Validator.TryValidateObject(this,
new ValidationContext(this),
null,
true /* validateAllProperties */);
}

Linq - reuse expression on child property

Not sure if what I am trying is possible or not, but I'd like to reuse a linq expression on an objects parent property.
With the given classes:
class Parent {
int Id { get; set; }
IList<Child> Children { get; set; }
string Name { get; set; }
}
class Child{
int Id { get; set; }
Parent Dad { get; set; }
string Name { get; set; }
}
If i then have a helper
Expression<Func<Parent,bool> ParentQuery() {
Expression<Func<Parent,bool> q = p => p.Name=="foo";
}
I then want to use this when querying data out for a child, along the lines of:
using(var context=new Entities.Context) {
var data=context.Child.Where(c => c.Name=="bar"
&& c.Dad.Where(ParentQuery));
}
I know I can do that on child collections:
using(var context=new Entities.Context) {
var data=context.Parent.Where(p => p.Name=="foo"
&& p.Childen.Where(childQuery));
}
but cant see any way to do this on a property that isnt a collection.
This is just a simplified example, actually the ParentQuery will be more complex and I want to avoid having this repeated in multiple places as rather than just having 2 layers I'll have closer to 5 or 6, but all of them will need to reference the parent query to ensure security.
If this isnt possible, my other thought was to somehow translate the ParentQuery expression to be of the given type so effectively:
p => p.Name=="foo";
turns into:
c => c.Dad.Name=="foo";
but using generics / some other form of query builder that allows this to retain the parent query and then just have to build a translator per child object that substitutes in the property route to the parent.
EDIT:
Following on from comments by #David morton
Initially that looks like I can just change from Expression to a delegate function and then call
.Where(ParentQuery()(c.Dad));
However I am using this in a wider repository pattern and cant see how I can use this with generics and predicate builders - I dont want to retrieve rows from the store and filter on the client (web server in this case). I have a generic get data method that takes in a base expression query. I then want to test to see if the supplied type implements ISecuredEntity and if it does append the securityQuery for the entity we are dealing with.
public static IList<T> GetData<T >(Expression<Func<T, bool>> query) {
IList<T> data=null;
var secQuery=RepositoryHelperers.GetScurityQuery<T>();
if(secQuery!=null) {
query.And(secQuery);
}
using(var context=new Entities.Context()) {
var d=context.GetGenericEntitySet<T>();
data=d.ToList();
}
return data;
}
ISecuredEntity:
public interface ISecuredEntity : IEntityBase {
Expression<Func<T, bool>> SecurityQuery<T>();
}
Example Entity:
public partial class ExampleEntity: ISecuredEntity {
public Expression<Func<T, bool>> SecurityQuery<T>() {
//get specific type expression and make generic
Type genType = typeof(Func<,>).MakeGenericType(typeof(ExampleEntity), typeof(bool));
var q = this.SecurityQuery(user);
return (Expression<Func<T, bool>>)Expression.Lambda(genType, q.Body, q.Parameters);
}
public Expression<Func<ExampleEntity, bool>> SecurityQuery() {
return e => e.OwnerId==currentUser.Id;
}
}
and repositoryHelpers:
internal static partial class RepositoryHelpers {
internal static Expression<Func<T, bool>> SecureQuery<T>() where T : new() {
var instanceOfT = new T();
if (typeof(Entities.ISecuredEntity).IsAssignableFrom(typeof(T))) {
return ((Entities.ISecuredEntity)instanceOfT).SecurityQuery<T>();
}
return null;
}
}
EDIT Here is the (eventual) solution
I ended up going back to using expressions, and using LinqKit Invoke. Note: for EF I also had to call .AsExpandable() on the entitySet
The key part is being able to call:
Product.SecureFunction(user).Invoke(pd.ParentProduct);
so that I can pass in the context into my parent query
My end classes look like:
public interface ISecureEntity {
Func<T,bool> SecureFunction<T>(UserAccount user);
}
public class Product : ISecureEntity {
public Expression<Func<T,bool>> SecureFunction<T>(UserAccount user) {
return SecureFunction(user) as Expression<Func<T,bool>>;
}
public static Expression<Func<Product,bool>> SecureFunction(UserAccount user) {
return f => f.OwnerId==user.AccountId;
}
public string Name { get;set; }
public string OwnerId { get;set; }
}
public class ProductDetail : ISecureEntity {
public Expression<Func<T,bool>> SecureFunction<T>(UserAccount user) {
return SecureFunction(user) as Expression<Func<T,bool>>;
}
public static Func<ProductDetail,bool> SecureFunction(UserAccount user) {
return pd => Product.SecureFunction(user).Invoke(pd.ParentProduct);
}
public int DetailId { get;set; }
public string DetailText { get;set; }
public Product ParentProduct { get;set; }
}
Usage:
public IList<T> GetData<T>() {
IList<T> data=null;
Expression<Func<T,bool>> query=GetSecurityQuery<T>();
using(var context=new Context()) {
var d=context.GetGenericEntitySet<T>().Where(query);
data=d.ToList();
}
return data;
}
private Expression<Func<T,bool>> GetSecurityQuery<T>() where T : new() {
var instanceOfT = new T();
if (typeof(Entities.ISecuredEntity).IsAssignableFrom(typeof(T))) {
return ((Entities.ISecuredEntity)instanceOfT).SecurityQuery<T>(GetCurrentUser());
}
return a => true; //returning a dummy query
}
}
Thanks for the help all.
You're overthinking it.
First, don't return an Expression<Func<Parent, bool>>, that'll require you to compile the expression. Return simply a Func<Parent, bool> instead.
Next, it's all in how you call it:
context.Children.Where(c => c.Name == "bar" && ParentQuery()(c.Dad));
context.Parents.Where(ParentQuery());

Resources