how to test fluent validations error message - tdd

I am trying to get to grips with TDD, I have reviewed some tutorials and am trying to implement tests on my validation classes that I have created using fluent validation.
public SomeFormValidator()
{
RuleFor(x => x.MyClass).NotNull()
.WithMessage("MyClass cannot be null");
}
I have looked at the TDD examples specifically for fluent validation and created a couple of tests
[Test]
public void Should_have_error_when_MyClass_is_null()
{
MyClass myClass = null;
SomeFormValidator.ShouldHaveValidationErrorFor(aup => aup.MyClass, myClass);
}
[Test]
public void Should_not_have_error_when_MyClass_is_not_null()
{
MyClass myClass = new MyClass();
SomeFormValidator.ShouldNotHaveValidationErrorFor(aup => aup.MyClass, myClass);
}
I would like to now test that the string "MyClass cannot be null" is returned when it is null. I have not been able to find anything covering returned message and I have not been able to work it out.

Thanks to the guidance of #Surgey I was able to come up with a solution that uses the fluent validation built in methods, in addition to that I have been able to better layout my test which I have added below
using FluentValidation.TestHelper;
using NUnit.Framework;
using MyProject.Models...
using MyProject...
namespace MyProject.Tests.Classes.Validation
{
[TestFixture]
public class SomeFormValidatorTest
{
private SomeFormValidator SomeFormValidator;
[SetUp]
public void Setup()
{
SomeFormValidator = new SomeFormValidator();
}
[Test]
public void Should_display_correct_error_message_MyClass_is_null()
{
//arrange
MyClass myClass = null;
//act
var result = SomeFormValidator.ShouldHaveValidationErrorFor(x => x.MyClass, myClass);
//assert
result.WithErrorMessage("MyClass is required");
//first attempt prior to finding WithErrorMessage exists
//foreach (var r in result)
//{
// Assert.AreEqual("MyClass is required", r.ErrorMessage);
//}
}
}
}
I am using result.WithErrorMessage as that is was is provided in the result but I have left the foreach in, but commented, as I find the error message produced by using Assert.AreEqual produce a better message in the test runner.

There is Arrange-Act-Assert (AAA) technique that helps to structure unit tests properly.
Arrange
First of all, you need to create a System Under Test (SUT) and inputs. In this case that are SomeFormValidator and SomeForm instances:
// arrange
var sut = new SomeFormValidator();
var someFormWithNullProp = new SomeForm { MyClass = null };
Act
Then you need to call the SUT to perform real work. For validators, that is the Validate() method call:
// act
ValidationResult result = sut.Validate<SomeForm>(someFormWithNullProp);
Assert
The last part of the unit test checks if the actual result matches the expectations:
// assert
Assert.False(result.IsValid);
Assert.AreEqual(
"MyClass cannot be null",
result.Errors.Single().ErrorMessage);

Related

how to unit test controller when automapper is used?

here's my controller
[POST("signup")]
public virtual ActionResult Signup(UserRegisterViewModel user)
{
if (ModelState.IsValid)
{
var newUser = Mapper.Map<UserRegisterViewModel, User>(user);
var confirmation = _userService.AddUser(newUser);
if (confirmation.WasSuccessful)
return RedirectToAction(MVC.Home.Index());
else
ModelState.AddModelError("Email", confirmation.Message);
}
return View(user);
}
here's my unit test:
[Test]
public void Signup_Action_When_The_User_Model_Is_Valid_Returns_RedirectToRouteResult()
{
// Arrange
const string expectedRouteName = "~/Views/Home/Index.cshtml";
var registeredUser = new UserRegisterViewModel { Email = "newuser#test.com", Password = "123456789".Hash()};
var confirmation = new ActionConfirmation<User>
{
WasSuccessful = true,
Message = "",
Value = new User()
};
_userService.Setup(r => r.AddUser(new User())).Returns(confirmation);
_accountController = new AccountController(_userService.Object);
// Act
var result = _accountController.Signup(registeredUser) as RedirectToRouteResult;
// Assert
Assert.IsNotNull(result, "Should have returned a RedirectToRouteResult");
Assert.AreEqual(expectedRouteName, result.RouteName, "Route name should be {0}", expectedRouteName);
}
Unit test failed right here.
var result = _accountController.Signup(registeredUser) as RedirectToRouteResult;
when I debug my unit test, I got following error message: "Missing type map configuration or unsupported mapping."
I think its because configuration is in web project, not the unit test project. what should I do to fix it?
You need to have the mapper configured, so in your test class set up, not the per-test setup, call the code to set up the mappings. Note, you'll also probably need to modify your expectation for the user service call as the arguments won't match, i.e, they are different objects. Probably you want a test that checks if the properties of the object match those of the model being passed to the method.
You should really use an interface for the mapping engine so that you can mock it rather than using AutoMapper otherwise it is an integration test not a unit test.
AutoMapper has an interface called IMappingEngine that you can inject into your controller using your IoC container like below (this example is using StructureMap).
class MyRegistry : Registry
{
public MyRegistry()
{
For<IMyRepository>().Use<MyRepository>();
For<ILogger>().Use<Logger>();
Mapper.AddProfile(new AutoMapperProfile());
For<IMappingEngine>().Use(() => Mapper.Engine);
}
}
You will then be able to use dependency injection to inject AutoMapper's mapping engine into your controller, allowing you to reference your mappings like below:
[POST("signup")]
public virtual ActionResult Signup(UserRegisterViewModel user)
{
if (ModelState.IsValid)
{
var newUser = this.mappingEngine.Map<UserRegisterViewModel, User>(user);
var confirmation = _userService.AddUser(newUser);
if (confirmation.WasSuccessful)
return RedirectToAction(MVC.Home.Index());
else
ModelState.AddModelError("Email", confirmation.Message);
}
return View(user);
}
You can read more about this here: How to inject AutoMapper IMappingEngine with StructureMap
Probably it is cool to abstract mapping into MappingEngine.
Sometimes I use following approach to IOC Automapper
In IOC builder:
builder.RegisterInstance(AutoMapperConfiguration.GetAutoMapper()).As<IMapper>();
where GetAutoMapper is:
public class AutoMapperConfiguration
{
public static IMapper GetAutoMapper()
{
var config = new MapperConfiguration(cfg =>
{
cfg.AddProfile<OrderModelMapperProfile>();
cfg.AddProfile<OtherModelMapperProfile>();
//etc;
});
var mapper = config.CreateMapper();
return mapper;
}
}
And finally in Controller ctor
public MyController(IMapper mapper)
{
_mapper = mapper;
}

TDD and MVC 3, Testing Models

I am trying to learn how to unit test and work with MVC 3 and I am getting stuck on the problem of How do I test two models. Here is the code
public class HomeController : Controller
{
private IRepository _repository;
public HomeController(IRepository repository)
{
_repository = repository;
}
//
// GET: /Home/
public ActionResult Index()
{
return View(_repository.GetAllGenres());
}
}
public interface IRepository
{
IEnumerable<Genre> GetAllGenres();
IEnumerable<Album> GetTopAlbums(int count);
}
and assume this is my Unit Testing
[TestFixture]
class HomeControllerTests
{
[Test]
public void Test1()
{
//Arrange
var controller = new HomeController(new InMemoryRepository());
var result = (ViewResult) controller.Index();
Assert.AreEqual(10,((IEnumerable<Genre>)result.ViewData.Model).Count());
}
[Test]
public void Test2()
{
var controller = new HomeController(new InMemoryRepository());
var result = (ViewResult) controller.Index();
//I Want to be able to do something like this
Assert.AreEqual(5,result.ViewData.Model.GetTopAlbums(5).Count);
}
}
Now my question is How exactly do I go about making something like I want work. Or do I create a ChildActionOnly Method that is responsible for returning the Top Albums.
Have you considered using a mocking framework to assist with you tests? For example you could make use of mock on your GetTopAlbums call. My preference is moq but there are several great mocking frameworks to choose from.
Note, this is a pretty simple example but you could easily create a test helper to generate a list with your expected number of albums:
[Test]
public void Index_Get_Should_Lookup_Top_Albums_And_Return_Index_View()
{
// arrange
var expectModel = new List<Album>
{
new Album{Artist= "joe", Tracks = 16},
new Album{Artist= "doe", Tracks = 23},
};
_repository.Setup(x => x.GetTopContacts(It.IsAny<int>())).Returns(expectModel);
var controller = new HomeController(_repository.Object);
// act
var result = controller.TopContacts();
var model = result.ViewData.Model as IEnumerable<Album>;
// assert
Assert.AreEqual(2, model.Count());
}
I have a very good solution for you. See the below two blog posts:
Generic Repository Pattern - Entity Framework, ASP.NET MVC and Unit
Testing Triangle
How to Work With Generic Repositories on ASP.NET MVC and Unit Testing
Them By Mocking
Basically, it is what #Jesse already suggested but those two posts also has some other features there which might be helpful for you.

Moq testing LINQ Where queries

I'm using EF 4.1 to build a domain model. I have a Task class with a Validate(string userCode) method and in it I want to ensure the user code maps to a valid user in the database, so:
public static bool Validate(string userCode)
{
IDbSet<User> users = db.Set<User>();
var results = from u in users
where u.UserCode.Equals(userCode)
select u;
return results.FirstOrDefault() != null;
}
I can use Moq to mock IDbSet no problem. But ran into trouble with the Where call:
User user = new User { UserCode = "abc" };
IList<User> list = new List<User> { user };
var users = new Mock<IDbSet<User>>();
users.Setup(x => x.Where(It.IsAny<Expression<Func<User, bool>>>())).Returns(list.AsQueryable);
Initialization method JLTi.iRIS3.Tests.TaskTest.SetUp threw exception.
System.NotSupportedException: System.NotSupportedException: Expression
references a method that does not belong to the mocked object:
x => x.Where<User>(It.IsAny<Expression`1>()).
Other than creating a level of indirection (eg, using a ServiceLocator to get an object that runs the LINQ and then mock that method) I can't think of how else to test this, but I want to make sure there is no way before I introduce another layer. And I can see this kind of LINQ queries will be needed quite often so the service objects can quickly spiral out of control.
Could some kind soul help? Thanks!
There is an article on MSDN highlighting how to mock using moq:
The gist of it is to represent linq to entities operations with linq to objects.
var mockSet = new Mock<DbSet<Blog>>();
mockSet.As<IQueryable<Blog>>().Setup(m => m.Provider).Returns(data.Provider);
mockSet.As<IQueryable<Blog>>().Setup(m => m.Expression).Returns(data.Expression);
mockSet.As<IQueryable<Blog>>().Setup(m => m.ElementType).Returns(data.ElementType);
mockSet.As<IQueryable<Blog>>().Setup(m => m.GetEnumerator()).Returns(data.GetEnumerator());
As Ladislav points out there are disadvantages to this as Linq To Objects is simply different to Linq to Entities so it may result in false positives. But it now being an MSDN article it does point that it is at least possible and perhaps recommended in some cases?
One thing that may of changed since the original answers to this post is that the Entity Framework team have opened up areas of Entity Framework in EF 6.0 to make it easier to mock it's inners.
Although I have not tried this, because IDBSet implements IEnumerable you might have to mock the enumerator method so the linq statements will pick up your list of users. You don't actually want to mock linq but by the looks of your code you want to test whether you are finding the right user based on the UserCode which I think is a valid unit test.
var user = new User { UserCode = "abc" };
var list = new List<User> { user };
var users = new Mock<IDbSet<User>>();
users.Setup(x => x.GetEnumerator()).Returns(list.GetEnumerator());
You might get a conflict with the non-generic version of the GetEnumerator but it this might help you on the right track.
Then you have to then place the mocked object on the data context which depends on other code that we don't see.
As I know Moq is able to set up only virtual methods of mocked object itself but you are trying to set up extensions (static) method - no way! These methods are absolutely outside of your mock scope.
Moreover that code is hard to test and requires too much initialization to be able to test it. Use this instead:
internal virtual IQueryable<User> GetUserSet()
{
return db.Set<User>();
}
public bool Validate(string userCode)
{
IQueryable<User> users = GetUserSet();
var results = from u in users
where u.UserCode.Equals(userCode)
select u;
return results.FirstOrDefault() != null;
}
You will just need to set up GetUserSet to return your list. Such testing has some major issues:
You are not testing the real implementation - in case of EF mocking sets is stupid approach because once you do it you change linq-to-entities to linq-to-objects. Those two are totally different and linq-to-entities is only small subset of linq-to-objects = your unit tests can pass with linq-to-objects but your code will fail at runtime.
Once you use this approach you cannot use Include because include is dependent on DbQuery / DbSet. Again you need integration test to use it.
This doesn't test that your lazy loading works
The better approach is removing your linq queries from Validate method - just call them as another virtual method of the object. Unit test your Validate method with mocked query methods and use integration tests to test queries themselves.
I found it easier just to write the stub:
internal class FakeDbSet<T> : IDbSet<T>where T : class
{
readonly HashSet<T> _data;
readonly IQueryable _query;
public FakeDbSet()
{
_data = new HashSet<T>();
_query = _data.AsQueryable();
}
public virtual T Find(params object[] keyValues)
{
throw new NotImplementedException("Derive from FakeDbSet<T> and override Find");
}
public T Add(T item)
{
_data.Add(item);
return item;
}
public T Remove(T item)
{
_data.Remove(item);
return item;
}
public T Attach(T item)
{
_data.Add(item);
return item;
}
public void Detach(T item)
{
_data.Remove(item);
}
Type IQueryable.ElementType
{
get { return _query.ElementType; }
}
Expression IQueryable.Expression
{
get { return _query.Expression; }
}
IQueryProvider IQueryable.Provider
{
get { return _query.Provider; }
}
IEnumerator IEnumerable.GetEnumerator()
{
return _data.GetEnumerator();
}
IEnumerator<T> IEnumerable<T>.GetEnumerator()
{
return _data.GetEnumerator();
}
public TDerivedEntity Create<TDerivedEntity>() where TDerivedEntity : class, T
{
return Activator.CreateInstance<TDerivedEntity>();
}
public T Create()
{
return Activator.CreateInstance<T>();
}
public ObservableCollection<T> Local
{
get
{
return new ObservableCollection<T>(_data);
}
}

Is there a way to make MsTest/Coded UI tests run in a new, random order every time?

Similar to this for Java:
How can I make my JUnit tests run in random order?
And opposite to this for .Net:
http://blogs.msdn.com/b/slange/archive/2010/06/02/ordering-method-execution-of-a-coded-ui-test.aspx
My reason is the same as in the first link - I wish to uncover any dependencies between the tests by shuffling the order every time they run.
Can this be done? I have to use MSTest because my tests drive GUI - they use Coded UI.
Since this hasn't been answered, I'll take a stab at it.
I don't know if the testing framework has this built in, but I would just code it myself. The simplest way might be to write a test method that calls all of the other test methods in a random order. You can be completely creative in the way you do this, you'll just want to set Playback.PlaybackSettings.ContinueOnError to true so the overall test doesn't fail when a single test fails.
I needed something similar so this may give you or anyone else a head start. You can just drop this in as it's own test class and it will automatically run every other unit test method in the same assembly a single time in a random order spanning unit test classes.
using System;
using System.Reflection;
using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace Company.UnitTests
{
[TestClass]
public class RandomizerTest
{
private class TestClassProxy
{
public object Instance { get; set; }
public Type Type { get; set; }
public Action ClassCleanup { get; set; }
public Action<TestContext> ClassInitialize { get; set; }
public Action TestCleanup { get; set; }
public Action TestInitialize { get; set; }
public List<Action> TestMethods { get; set; }
}
[TestMethod]
public void TestRandom()
{
// ARRANGE
// attributes we'll be using to build our proxies (change these for NInject, other UT frameworks)
var classInitializeAttributeType = typeof (ClassInitializeAttribute);
var classCleanupAttributeType = typeof (ClassCleanupAttribute);
var testInitializeAttributeType = typeof (TestInitializeAttribute);
var testCleanupAttributeType = typeof (TestCleanupAttribute);
var testMethodAttributeType = typeof (TestMethodAttribute);
var proxies = (
from type in Assembly.GetExecutingAssembly().GetTypes()
where
type != typeof (RandomizerTest) && // don't include this class (infinite-loop)
type.GetCustomAttributes(typeof (TestClassAttribute), false).Length > 0 // only classes attributed with [TestClass]
let methods = type.GetMethods() // keep the methods for re-use
let instance = Activator.CreateInstance(type)
select new TestClassProxy
{
Type = type,
Instance = instance,
ClassInitialize = // select and wrap the method invokes inside an Action for re-use
methods
.Where(λ =>
λ.GetCustomAttributes(classInitializeAttributeType, false).Any())
.Select(λ => (Action<TestContext>) (tc => λ.Invoke(instance, new object[] { tc })))
.FirstOrDefault() ?? delegate { },
ClassCleanup =
methods
.Where(λ =>
λ.GetCustomAttributes(classCleanupAttributeType, false).Any())
.Select(λ => (Action) (() => λ.Invoke(instance, null)))
.FirstOrDefault() ?? delegate { },
TestInitialize =
methods
.Where(λ =>
λ.GetCustomAttributes(testInitializeAttributeType, false).Any())
.Select(λ => (Action) (() => λ.Invoke(instance, null)))
.FirstOrDefault() ?? delegate { },
TestCleanup =
methods
.Where(λ =>
λ.GetCustomAttributes(testCleanupAttributeType, false).Any())
.Select(λ => (Action) (() => λ.Invoke(instance, null)))
.FirstOrDefault() ?? delegate { },
TestMethods =
methods
.Where(λ =>
λ.GetCustomAttributes(testMethodAttributeType, false).Any())
.Select(λ => (Action) (() => λ.Invoke(instance, null))).ToList(),
}).ToList();
var random = new Random();
// ACT
// Note that the following may not work depending on how you developed your unit tests.
// If they're sharing state in any way (SQL DB, etc.) this may not be what you want.
// If that's the case alter the code below to only randomly sample test methods inside each class
// so that you can isolate tests per test class.
// This methodology assumes the cardinal rule: All unit tests are atomic. (given their proper setup/teardown)
// Plus if you're testing in a random order this is likely what you're after anyway.
// initialize all classes
foreach (var testClassProxy in proxies)
{
testClassProxy.ClassInitialize(null);
}
// run all test methods in a random order spanning all test classes until we run out
while (proxies.Count > 0)
{
// get random test class proxy
var proxy = proxies[random.Next(0, proxies.Count)];
// get random test method from proxy
var testMethod = proxy.TestMethods[random.Next(0, proxy.TestMethods.Count)];
// run test initialize
proxy.TestInitialize();
// run test method
testMethod(); // (ASSERT)
// run test cleanup
proxy.TestCleanup();
// remove test method from processing
proxy.TestMethods.Remove(testMethod);
// still have methods?
if (proxy.TestMethods.Count > 0)
{
continue;
}
// no, run class cleanup routine
proxy.ClassCleanup();
// remove the proxy from processing
proxies.Remove(proxy);
}
}
}
}

ObjectSet query not returning added EntityObject until SaveChanges() called

I think I'm missing something very simple here.
I have an EF4 ObjectContext that contains an ObjectSet of type Thing, which is mapped to a table in my database called Things. If I add a Thing to the Things ObjectSet, that Thing is not visible in Things until I call SaveChanges() on the ObjectContext.
So, in the following test fixture, AddToThings_AddsItemsToContext_WithSaveChanges passes but AddToThings_AddsItemsToContext_WithoutSaveChanges fails:
[TestFixture]
public class Ef4Tests
{
[SetUp]
public void SetUp()
{
var ef4PocEntities = new Ef4PocEntities();
ef4PocEntities.DeleteDatabase();
ef4PocEntities.CreateDatabase();
}
// this test passes
[Test]
public void AddToThings_AddsItemsToContext_WithSaveChanges()
{
var ef4PocEntities = new Ef4PocEntities();
Assert.AreEqual(0, ef4PocEntities.Things.Count());
ef4PocEntities.AddToThings(new Thing {Name = "Bob"});
ef4PocEntities.SaveChanges();
Assert.AreEqual(1, ef4PocEntities.Things.Count());
}
// this test fails
[Test]
public void AddToThings_AddsItemsToContext_WithoutSaveChanges()
{
var ef4PocEntities = new Ef4PocEntities();
Assert.AreEqual(0, ef4PocEntities.Things.Count());
ef4PocEntities.AddToThings(new Thing {Name = "Bob"});
Assert.AreEqual(1, ef4PocEntities.Things.Count());
}
}
Is there a way to do what I want? I.e. add Entities to an ObjectSet and have them visible without saving to the database?
The answer is here: Finding Entity Framework contexts.

Resources