Testing repository method - tdd

As the title suggests I'm trying to test a method, unfortunately I appear to be going wrong some where. The method should only return customers that have and ID = 1
Here is my test
[TestMethod]
public void Returns_Correct_Number_Of_Workout_Dates_For_Valid_UserId()
{
//Arrange
List<GymSession> gymSessions = new List<GymSession>();
Customer cust = new Customer();
cust.CustomerId = 1;
gymSessions.Add(new GymSession() { Customer = cust, SessionId = 1, Date = new DateTime(2010, 1, 1) });
gymSessions.Add(new GymSession() { Customer = cust, SessionId = 2, Date = new DateTime(2010, 1, 2) });
gymSessions.Add(new GymSession() { SessionId = 3, Date = new DateTime(2010, 1, 3) });
gymSessions.Add(new GymSession() { Customer = cust, SessionId = 4, Date = new DateTime(2010, 1, 4) });
var mockRepos = new Moq.Mock<IGymSessionRepository>();
mockRepos.Setup(g => g.GymSession()).Returns(gymSessions.AsQueryable());
//Act
var result = mockRepos.Object.GetWorkoutDatesByCustomerId(1);
//Assert
Assert.AreEqual(3, result.Count());
}
Here is the repository method I'm trying to test
public IQueryable<GymSession> GetWorkoutDatesByCustomerId(int userId)
{
var gymSess = db.GymSessions.Where<GymSession>(g => g.Customer.CustomerId == userId);
return gymSess;
}
The idea is that setup has all the customers, and the method then filters them. The count never seems to apply the filter. Any ideas?

It appears that you really want to stub the call to db.GymSessions and that you should test a concrete GymSessionRepository instance. Traditionally, there are two ways to do this (apart from intercepting calls using aspect-oriented programming):
1) Give your repository an explicit dependency on db and require it in the repository constructor. Here's what I mean, where I'm using IDatabase to represent db:
public class GymSessionRepository: IGymSessionRepository {
private IDatabase db;
public GymSessionRepository(IDatabase db) {
this.db = db;
}
}
// Then in your test ...
var mockDb = new Moq.Mock<IDatabase>();
mockDb.Setup(d => d.GymSessions()).Returns(gymSessions.AsQueryable());
GymSessionRepository repository = new GymSessionRepository(mockDb);
// ... and so on
2) (Less desirable, but sometimes necessary) Expose the method you want to stub as a virtual member, mock the concrete object you're testing, and stub the behavior directly on the class under test:
public class GymSessionRepository {
// Because this is virtual, you can override it in your mock object
protected virtual List<GymSession> GymSessions() {
return this.db.GymSessions.AsQueryable();
}
}
// In your test code here: notice the mock object is your concrete class,
// because your test targets another method on that class, not a method
// on an arbitrary implementation (like a mock based on its interface)
var mockRepos = new Moq.Mock<GymSessionRepository>();
// Override its virtual method; take control for your test
mockRepos.Setup(g => g.GymSessions()).Returns(gymSessions.AsQueryable());
Depending on the mocking framework, the second technique is known as using a transparent or partial mock. If you find yourself using it often, it may be a sign that your code is overly-coupled (and it can get confusing fast).

Related

Instantiate new System.Web.Http.OData.Query.ODataQueryOptions in nunit test of ASP.NET Web API controller

I have an ASP.NET MVC4 Web API project with an ApiController-inheriting controller that accepts an ODataQueryOptions parameter as one of its inputs.
I am using NUnit and Moq to test the project, which allow me to setup canned responses from the relevant repository methods used by the ApiController. This works, as in:
[TestFixture]
public class ProjectControllerTests
{
[Test]
public async Task GetById()
{
var repo = new Mock<IManagementQuery>();
repo.Setup(a => a.GetProjectById(2)).Returns(Task.FromResult<Project>(new Project()
{
ProjectID = 2, ProjectName = "Test project", ProjectClient = 3
}));
var controller = new ProjectController(repo.Object);
var response = await controller.Get(2);
Assert.AreEqual(response.id, 2);
Assert.AreEqual(response.name, "Test project");
Assert.AreEqual(response.clientId, 3);
}
}
The challenge I have is that, to use this pattern, I need to pass in the relevant querystring parameters to the controller as well as the repository (this was actually my intent). However, in the case of ODataQueryOptions-accepting ApiController methods, even in the cases where I would like to use just the default parameters for ODataQueryOptions, I need to know how to instantiate one. This gets tricky:
ODataQueryOptions does not implement an interface, so I can't mock it directly.
The constructor requires an implementation of System.Web.Http.OData.ODataQueryContext, which requires an implementation of something implementing Microsoft.Data.Edm.IEdmModel, for which the documentation is scarce and Visual Studio 2012 Find References and View Call Hierarchy do not provide insight (what implements that interface?).
What do I need to do/Is there a better way of doing this?
Thanks.
Looks like someone else already answered this in the comments here, but it's not a complete solution for my use-case (see comment below):
ODataModelBuilder modelBuilder = new ODataConventionModelBuilder();
modelBuilder.EntitySet<Customer>("Customers");
var opts = new ODataQueryOptions<Customer>(new ODataQueryContext(modelBuilder.GetEdmModel(),typeof(Customer)), request);
This is the solution I have been using in my NUnit tests to inject ODataQueryOptions
private static IEdmModel _model;
private static IEdmModel Model
{
get
{
if (_model == null)
{
var builder = new ODataConventionModelBuilder();
var baseType = typeof(MyDbContext);
var sets = baseType.GetProperties().Where(c => c.PropertyType.IsGenericType && c.PropertyType.GetGenericTypeDefinition() == typeof(IDbSet<>));
var entitySetMethod = builder.GetType().GetMethod("EntitySet");
foreach (var set in sets)
{
var genericMethod = entitySetMethod.MakeGenericMethod(set.PropertyType.GetGenericArguments());
genericMethod.Invoke(builder, new object[] { set.Name });
}
_model = builder.GetEdmModel();
}
return _model;
}
}
public static ODataQueryOptions<T> QueryOptions<T>(string query = null)
{
query = query ?? "";
var url = "http://localhost/Test?" + query;
var request = new HttpRequestMessage(HttpMethod.Get, url);
return new ODataQueryOptions<T>(new ODataQueryContext(Model, typeof(T)), request);
}

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);
}
}
}
}

Resources