I am using Entity Framework 6 and Moq framework. Currently I am writing a few Unit Tests where in each test I need to set up a dataset with the appropriate type for each test.
One of the unit tests looks like this:
[TestMethod]
public async Task GetAllCaseCategories_WithEmptyDataset_ReturnsEmpty()
{
var data = new List<DataAccessLayer.Tables.CaseCategory>(){};
var mockContext = GetMockContextWithCaseCategoryDataSetAsync(data);
var mockLogger = new Mock<IDatabaseContextLogging>();
DatabaseTablesAccess databaseAccess = new DatabaseTablesAccess(mockDatabaseContext.Object, mockLogger.Object);
List<OneCaseCategory> caseCategories = await databaseAccess.GetAllCaseCategories();
Assert.IsTrue(caseCategories.Count().Equals(0), "caseCategories should not contain any items.");
}
The method that generates the database context mock object is contain in the method called "GetMockContextWithCaseCategoryDataSetAsync". Here it is:
public Mock<Context> GetMockContextWithCaseCategoryDataSetAsync(List<CaseCategory> data)
{
var mockCaseCategorySet = new Mock<DbSet<CaseCategory>>() { };
mockCaseCategorySet.As<IQueryable<CaseCategory>>().Setup(x => x.Provider).Returns(new TestDbAsyncQueryProvider<CaseCategory>(data.AsQueryable().Provider));
mockCaseCategorySet.As<IQueryable<CaseCategory>>().Setup(x => x.Expression).Returns(data.AsQueryable().Expression);
mockCaseCategorySet.As<IQueryable<CaseCategory>>().Setup(x => x.ElementType).Returns(data.AsQueryable().ElementType);
mockCaseCategorySet.As<IDbAsyncEnumerable<CaseCategory>>().Setup(x => x.GetAsyncEnumerator()).Returns(new TestDbAsyncEnumerator<CaseCategory>(data.AsQueryable().GetEnumerator()));
mockCaseCategorySet.As<IQueryable<CaseCategory>>().Setup(x => x.GetEnumerator()).Returns(data.AsQueryable().GetEnumerator());
Mock<Context> m = new Mock<Context>();
m.Setup(x => x.CaseCategories).Returns(mockCaseCategorySet.Object);
return m;
}
I have multiple tables in the data access object and I have written a method for each one that returns the data access object with the appropriate type of data bound to the correct table in the mock object. I would like to generalize this and here is my attempt:
public Mock<Context> GetMockContextWithCaseCategoryDataSetAsync<T>(List<T> data) where T : class
{
var mockCaseCategorySet = new Mock<DbSet<T>>() { };
mockCaseCategorySet.As<IQueryable<T>>().Setup(x => x.Provider).Returns(new TestDbAsyncQueryProvider<T>(data.AsQueryable().Provider));
mockCaseCategorySet.As<IQueryable<T>>().Setup(x => x.Expression).Returns(data.AsQueryable().Expression);
mockCaseCategorySet.As<IQueryable<T>>().Setup(x => x.ElementType).Returns(data.AsQueryable().ElementType);
mockCaseCategorySet.As<IDbAsyncEnumerable<T>>().Setup(x => x.GetAsyncEnumerator()).Returns(new TestDbAsyncEnumerator<T>(data.AsQueryable().GetEnumerator()));
mockCaseCategorySet.As<IQueryable<T>>().Setup(x => x.GetEnumerator()).Returns(data.AsQueryable().GetEnumerator());
Mock<Context> m = new Mock<Context>();
m.Setup(x => x.?).Returns(mockCaseCategorySet.Object);
return m;
}
Everything is good up until that second last line in the generic version of the method where I am setting up which table returns the mocked object. I am lost as to how (if even possible) I control which table is used based on the generic passed in.
I would like to use it like this:
var context = GetMockContextWithCaseCategoryDataSetAsync<CaseCategory>(data);
I don't see a way to do what you're trying to do unless you also access the DbSets by the generic Set<TEntity> method (like _dbContext.Set<Salary>().Select(x => x.Id)).
An alternative setup that I have been using and that is sort of generic is to create a "MockedDbContext" class that I reuse in all tests accessing the database. This usually looks something like this;
public class MockedDbContext
{
public MockedDbContext() => MockContextProperties();
public Mock<MyDbContext> ContextMock { get; } = new Mock<MyDbContext>(MockBehavior.Loose);
public HashSet<Employee> Employees { get; } = new HashSet<Employee>();
public HashSet<Salary> Salaries { get; } = new HashSet<Salary>();
// etc...
private void MockContextProperties()
{
SimulateGet(x => x.Employees, Employees);
SimulateGet(x => x.Salaries, Salaries);
// etc...
}
private void SimulateGet<TModel>(
Expression<Func<MyDbContext, DbSet<TModel>>> dbSetExpression,
HashSet<TModel> mockedData) where TModel : class
{
ContextMock.SetupGet(dbSetExpression).Returns(new InMemoryDbSet<TModel>(mockedData));
}
public void VerifyThatSaveWasCalled() => ContextMock.Verify(x => x.SaveChanges());
public void VerifyThatSaveWasNotCalled() => ContextMock.Verify(x => x.SaveChanges(), Times.Never);
}
I use it like this;
[TestFixture]
public class When_getting_some_data
{
private readonly MockedDbContext _mockedDbContext = new MockedDbContext();
private readonly Fixture _fixture = new Fixture();
private string _organizationNumber = "yyyyyy-xxx";
private readonly DateTime _created = new DateTime(2022, 2, 2);
private SomeInformation _result;
[OneTimeSetUp]
public void Initialize()
{
var salary = _fixture.Build<Salary>().With(o => o.Created, _created).Create();
_mockedDbContext.Salaries.Add(salary);
_result = new SomeClass(_mockedDbContext.ContextMock.Object).GetSomeInformation(_organizationNumber);
}
[Test]
public void Then_returned_data_is_as_expected()
{
_result.Should().NotBeNull();
_result.Created.Should().Be(_created);
}
}
And It internally uses an InMemoryDbSet<T> that looks like this;
/// <summary>
/// The in-memory database set, taken from Microsoft's online example (http://msdn.microsoft.com/en-us/ff714955.aspx)
/// and modified to be based on DbSet instead of ObjectSet.
/// </summary>
/// <typeparam name="T">The type of DbSet.</typeparam>
public class InMemoryDbSet<T> : DbSet<T>, IQueryable<T> where T : class
{
private static readonly HashSet<T> StaticData = new HashSet<T>();
private readonly HashSet<T> _nonStaticData;
/// <summary>
/// Creates an instance of the InMemoryDbSet using the default static backing store.This means
/// that data persists between test runs, like it would do with a database unless you
/// cleared it down.
/// </summary>
public InMemoryDbSet() : this(true) { }
/// <summary>
/// This constructor allows you to pass in your own data store, instead of using
/// the static backing store.
/// </summary>
/// <param name="data">A place to store data.</param>
public InMemoryDbSet(HashSet<T> data) => _nonStaticData = data;
/// <summary>
/// Creates an instance of the InMemoryDbSet using the default static backing store.This means
/// that data persists between test runs, like it would do with a database unless you
/// cleared it down.
/// </summary>
/// <param name="clearDownExistingData">True to clear existing data</param>
public InMemoryDbSet(bool clearDownExistingData)
{
if (clearDownExistingData)
Clear();
}
public Func<IEnumerable<T>, object[], T> FindFunction { get; set; }
public Type ElementType => Data.AsQueryable().ElementType;
public Expression Expression => Data.AsQueryable().Expression;
public IQueryProvider Provider => Data.AsQueryable().Provider;
IQueryProvider IQueryable.Provider => Data.AsQueryable().Provider;
public new ObservableCollection<T> Local => new ObservableCollection<T>(Data);
/// <summary>
/// The non static backing store data for the InMemoryDbSet.
/// </summary>
private HashSet<T> Data => _nonStaticData ?? StaticData;
public void Clear() => Data.Clear();
public override EntityEntry<T> Add(T entity)
{
Data.Add(entity);
return null;
}
public new T Attach(T entity)
{
Data.Add(entity);
return entity;
}
public TDerivedEntity Create<TDerivedEntity>() where TDerivedEntity : class, T => Activator.CreateInstance<TDerivedEntity>();
public T Create() => Activator.CreateInstance<T>();
public new virtual T Find(params object[] keyValues)
{
if (FindFunction != null)
{
return FindFunction(Data, keyValues);
}
throw new NotImplementedException("Derive from InMemoryDbSet and override Find, or provide a FindFunction.");
}
public new T Remove(T entity)
{
Data.Remove(entity);
return entity;
}
public IEnumerator<T> GetEnumerator() => Data.GetEnumerator();
}
This saves a lot of work when writing unit tests and is kind of a one time setup which is what I think you were looking for.
Related
I have a class that takes in an IMapper in the constructor like this
public Foo(IMapper mapper)
In the code for Foo I have this line
var dao = _mapper.Map<BaseDAO>(obj);
BaseDAO has 3 subtypes that in the real code I have set up like this
CreateMap<Base, BaseDAO>()
.Include<Child1, Child1DAO>()
.Include<Child2, Child2DAO>()
.Include<Child3, Child3DAO>();
I would like to mock out the above line
var dao = _mapper.Map<BaseDAO>(obj);
so that if a Child1 is passed in then a Child1DAO will be returned and the same for the other subtypes. I tried to stub out IMapper but the following method returns an error saying that
Child1DAO cannot be implicitly converted to a TDestination
and I tried to mock out IMapper but could not get that to work either.
public TDestination Map<TDestination>(object source)
{
return new Child1DAO();
}
Any ideas?
For the purposes of this example, assume the following class is the subject under test
public class Foo {
private IMapper mapper;
public Foo(IMapper mapper) {
this.mapper = mapper;
}
public BaseDAO Bar(object obj) {
var dao = mapper.Map<BaseDAO>(obj);
return dao;
}
}
Where the IMapper dependency has the following contract defined
public interface IMapper {
/// <summary>
/// Execute a mapping from the source object to a new destination object.
/// The source type is inferred from the source object.
/// </summary>
/// <typeparam name="TDestination">Destination type to create</typeparam>
/// <param name="source">Source object to map from</param>
/// <returns>Mapped destination object</returns>
TDestination Map<TDestination>(object source);
//...
}
The following test demonstrates, using moq,
Mock IMapper Returning Derived Classes where Base Expected
[TestClass]
public class TestClass {
[TestMethod]
public void _TestMethod() {
//Arrange
var mock = new Mock<IMapper>();
var foo = new Foo(mock.Object);
mock
//setup the mocked function
.Setup(_ => _.Map<BaseDAO>(It.IsAny<object>()))
//fake/stub what mocked function should return given provided arg
.Returns((object arg) => {
if (arg != null && arg is Child1)
return new Child1DAO();
if (arg != null && arg is Child2)
return new Child2DAO();
if (arg != null && arg is Child3)
return new Child3DAO();
return null;
});
var child1 = new Child1();
//Act
var actual = foo.Bar(child1);
//Assert
Assert.IsNotNull(actual);
Assert.IsInstanceOfType(actual, typeof(BaseDAO));
Assert.IsInstanceOfType(actual, typeof(Child1DAO));
}
}
Having some issues getting my repository to retrieve information - keeps coming back null. Any Thoughts would be appreciated - new to this and teaching myself.
Repository:
public class CustomerRepository : ICustomerRepository
{
private masterContext context;
public CustomerRepository(masterContext context)
{
this.context = context;
}
public IEnumerable<Customer> GetCustomers()
{
return context.Customer.ToList();
}
public Customer GetCustomerById(int customerId)
{
var result = (from c in context.Customer where c.CustomerId == customerId select c).FirstOrDefault();
return result;
}
public void Save()
{
context.SaveChanges();
}
Controller:
public class CustomerController : Controller
{
private readonly ICustomerRepository _repository = null;
public ActionResult Index()
{
var model = (List<Customer>)_repository.GetCustomers();
return View(model);
}
public ActionResult New()
{
return View();
}
}
MasterContext which i had efc make:
public partial class masterContext : DbContext
{
public masterContext(DbContextOptions<masterContext> options)
: base(options)
{ }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Customer>(entity =>
{
entity.Property(e => e.CustomerName).IsRequired();
});
}
public virtual DbSet<Customer> Customer { get; set; }
public virtual DbSet<Order> Order { get; set; }
}
I think you need to create instances of you Context and your Repository. So in your Controller you need to something like this:
private masterContext context = new masterContext();
private ICustomerRepository repository = new CustomerRepository(context);
I assume that you're not using Dependency injection ... if so you just need to create a Constructor for your Controller that takes CustomerRepository as argument:
public CustomerController(ICustomerRepository _repository) {
repository = _repository;
}
If you did not configure your database context, look here: https://docs.efproject.net/en/latest/platforms/aspnetcore/new-db.html
This will than enable you the dependency injection. Everything you than need to do for the Repository is to use
services.AddScoped<ICustomerRepository,
CustomerRepository>();
And I think it could be good to remove the ToList() in the Repository class and remove the Cast List<Customer> in your Controller and use ToList() instead, if it's really needed. Because if you're using it in the View the ienumerable could also work.
I have a simple Http module:
public class CustomLoggingModule : IHttpModule
{
public void Init(HttpApplication context)
{
context.BeginRequest += BeginRequest;
context.EndRequest += EndRequest;
}
public void BeginRequest(object sender, EventArgs eventArgs)
{
//some code
}
public void EndRequest(object sender, EventArgs eventArgs)
{
//some
}
public void Dispose()
{
}
}
How can I unit test this? Especially how is it possible to mock events? Can anyone give some simple example?
Not sure why you have decided to hardwire the dependencies as new LogService() and new HttpContextWrapper(HttpContext.Current) within the CustomLoggingModule. If want to test whether LogInfo() method is called or not, it becomes lot easier if you can externalize these dependencies so you can inject stubbed/mocked version etc.
Also your question does not state that you are using an IOC container. You can register the HttpModule with the container and provide external dependencies at runtime. Your question also does not state that using an isoloation/mock object framework.
Therefore I will provide you with a solution that you can verify whether LogInfo method is called, using hand written stubs and mocks.
To achieve this, we need to refactor CustomLoggingModule a bit, so it becomes more testable.
System Under Test (SUT)
public class CustomLoggingModule : IHttpModule
{
public ILogService LogService { get; set; }
public Func<ILoggingHttpContextWrapper> LogginHttpContextWrapperDelegate { get; set; }
public void Init(HttpApplication context) {
context.BeginRequest += BeginRequest;
context.EndRequest += EndRequest;
}
public CustomLoggingModule() {
LogginHttpContextWrapperDelegate = () => new LoggingHttpContextWrapper();
}
public void BeginRequest(object sender, EventArgs eventArgs) {
LogService.LogInfo(LogginHttpContextWrapperDelegate().HttpContextWrapper);
}
public void EndRequest(object sender, EventArgs eventArgs) {
//some
}
public void Dispose(){ }
}
As you see above, I have introduced 2 additional properties - ILogService so I can provide a Mocked verion and a delegate Func which allows me to stub the
new HttpContextWrapper(HttpContext.Current);
public interface ILoggingHttpContextWrapper {
HttpContextWrapper HttpContextWrapper { get; }
}
public class LoggingHttpContextWrapper : ILoggingHttpContextWrapper
{
public LoggingHttpContextWrapper() {
HttpContextWrapper = new HttpContextWrapper(HttpContext.Current);
}
public HttpContextWrapper HttpContextWrapper { get; private set; }
}
And then your real ILogService
public interface ILogService {
void LogInfo(HttpContextWrapper httpContextWrapper);
}
public class LogService : ILogService {
public void LogInfo(HttpContextWrapper httpContextWrapper)
{
//real logger implementation
}
}
Unit Test :
You would create a MockLoggerService, so you can verify the interaction i,e whether the LogInfo() method was called, etc. You also need a stubbed LoggingHttpContextWrapper to provide the fake HttpContextWrapper to the SUT (System Under Test)/ CustomLoggingModule.
public class StubLoggingHttpContextWrapper : ILoggingHttpContextWrapper
{
public StubLoggingHttpContextWrapper(){}
public HttpContextWrapper HttpContextWrapper { get; private set; }
}
public class MockLoggerService : ILogService
{
public bool LogInfoMethodIsCalled = false;
public void LogInfo(HttpContextWrapper httpContextWrapper) {
LogInfoMethodIsCalled = true;
}
}
MockLoggerService is very important. It is not the real logger service, but it is the mocked version. When we do public class MockLoggerService : ILogService this means that we are providing another layer of indirection to the logger service so we can verify the interaction of the behaviour.
You also notice that I have provided a boolean variable to verify whether the LogInfo method is called or not. This allows me to call this method from the SUT, and verify whether the method being called or not.
Now Your Unit Test can be implemented as below.
[TestMethod]
public void CustomLoggingModule_BeginRequest_VerifyLogInfoMethodIsCalled()
{
var sut = new CustomLoggingModule();
var loggerServiceMock = new MockLoggerService();
var loggingHttpContextWrapperStub = new StubLoggingHttpContextWrapper();
sut.LogService = loggerServiceMock;
sut.LogginHttpContextWrapperDelegate = () => loggingHttpContextWrapperStub;
sut.BeginRequest(new object(), new EventArgs());
Assert.IsTrue(loggerServiceMock.LogInfoMethodIsCalled);
}
I had the same issue with my custom http module and decided I won't give up that easily and will do all I can to trigger the BeginRequest event in unit test. I had to actually read through the source code of HttpApplication class and use reflection to invoke the method.
[TestMethod]
public void EventTriggered_DoesNotError()
{
using (var application = new HttpApplication())
{
var module = new CustomLoggingModule();
module.Init(application);
FireHttpApplicationEvent(application, "EventBeginRequest", this, EventArgs.Empty);
}
}
private static void FireHttpApplicationEvent(object onMe, string invokeMe, params object[] args)
{
var objectType = onMe.GetType();
object eventIndex = (object)objectType.GetField(invokeMe, System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic).GetValue(onMe);
EventHandlerList events = (EventHandlerList)objectType.GetField("_events", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic).GetValue(onMe);
EventHandler handler = (EventHandler)events[eventIndex];
Delegate[] delegates = handler.GetInvocationList();
foreach (Delegate dlg in delegates)
{
dlg.Method.Invoke(dlg.Target, args);
}
}
I want generic/oneline statements for structuremap configuration . please see the following code and suggest the changes :
Structuremap configuration class :
class StructureMapTestConfigurationRegistry : Registry
{
/// <summary>
/// Initializes a new instance of the <see cref="DependencyConfigurationRegistry"/> class.
/// </summary>
public StructureMapTestConfigurationRegistry()
{
For<Repository.IRepository<Report>>().Use(MockObjectGenerator<Report>.RepositoryMockSetup());
For<Repository.IRepository<RelatedContent>>().Use(MockObjectGenerator<RelatedContent>.RepositoryMockSetup());
For<Repository.IRepository<Tags>>().Use(MockObjectGenerator<Tags>.RepositoryMockSetup());
For<Repository.IRepository<ArticleTag>>().Use(MockObjectGenerator<ArticleTag>.RepositoryMockSetup());
For<Repository.IRepository<ReferenceBookTag>>().Use(MockObjectGenerator<ReferenceBookTag>.RepositoryMockSetup());
For<Repository.IRepository<EventsTag>>().Use(MockObjectGenerator<EventsTag>.RepositoryMockSetup());
For<Repository.IRepository<CountryFactfileTag>>().Use(MockObjectGenerator<CountryFactfileTag>.RepositoryMockSetup());
}
BootStrapper Class :
public static class TestBootstrapper
{
public static void TestConfigureStructureMap()
{
ObjectFactory.Container.Dispose();
ObjectFactory.Initialize(o => o.AddRegistry(new StructureMapTestConfigurationRegistry()));
ObjectFactory.Container.AssertConfigurationIsValid();
}
}
MockObjectGenerator Class :
public static class MockObjectGenerator<TEntity> where TEntity : class
{
private static List<TEntity> DummyTable
{
get
{
return MockEntities.GetData<TEntity>();
}
}
public static IRepository<TEntity> RepositoryMockSetup()
{
Mock<IRepository<TEntity>> repository = new Mock<IRepository<TEntity>>(MockBehavior.Strict);
repository.Setup(o => o.Fetch(It.IsAny<Expression<Func<TEntity, bool>>>())).Returns((Expression<Func<TEntity, bool>> i) => DummyTable.Where(i.Compile()).ToList());
repository.Setup(o => o.Create(It.IsAny<IEnumerable<TEntity>>())).Callback<IEnumerable<TEntity>>(items => DummyTable.AddRange(items));
repository.Setup(o => o.Delete(It.IsAny<TEntity>())).Callback<TEntity>(item => DummyTable.Remove(item));
}
}
**Mock Entities Class :**
public static class MockEntities
{
public static Dictionary<string, dynamic> MockData = new Dictionary<string, dynamic>();
public static void LoadData()
{
MockData.Add(typeof(CMSModel.Article).Name, ArticleTestData.GetTestRecords());
MockData.Add(typeof(CMSModel.ArticleTag).Name, RelatedArticleContentTestData.GetTestRecords());
}
public static List<T> GetData<T>() where T : class
{
return (List<T>)MockData[typeof(T).Name];
}
}
Note :
This has been done so that in actual unit test , We dont have to write setup methods since that is done while creating dependent object using structuremap.
It works fine, but I want to refactor the configuration file code to generic
I have writen it for implentation like this :
For(typeof(Repository.IRepository<>)).Use(typeof(Repository.Repository<>));
is it possible for unit test configuration ?
It is possible, though you'd need to specify all types entity types that are going to be used and pass them as Types. And you'll need to use non-generic version of functions (to be able to write For(type) instead of For). That way all your functions would work only on type variables and would look like simple methods.
Not sure if it has been asked before, here is the question.
Code first:
public class Customer {
public string Password { get; set; }
public string PasswordHash { get; set; }
}
public class CustomerService {
private ICustomerRepository _repo;
public CustomerService(ICustomerRepository repo) {
_repo = repo;
}
public int? AddCustomer(Customer customer) {
customer.PasswordHash = SHA1Hasher.ComputeHash(customer.Password);
return _repo.Add(customer);
}
}
public interface ICustomerRepository {
int? Add(Customer c);
}
public class CustomerRepository : ICustomerRepository {
int? AddCustomer(Customer customer) {
// call db and return identity
return 1;
}
}
[TestClass]
public class CustomerServiceTest {
[TestMethod]
public void Add_Should_Compute_Password_Hash_Before_Saving() {
var repoMock = new Mock<ICustomerRepository>();
//how do I make sure the password hash was calculated before passing the customer to repository???
}
}
How do I verify that CustomerService assigned the PasswordHash before passing the customer to repository?
There are several approaches you could take. Although not necessarily the best solution, here's one that doesn't require you to change your existing API. It assumes that SHA1Hasher.ComputeHash is a public method.
[TestClass]
public class CustomerServiceTest
{
[TestMethod]
public void Add_Should_Compute_Password_Hash_Before_Saving()
{
var customer = new Customer { Password = "Foo" };
var expectedHash = SHA1Hasher.ComputeHash(customer.Password);
var repoMock = new Mock<ICustomerRepository>();
repoMock
.Setup(r => r.Add(It.Is<Customer>(c => c.PasswordHash == expectedHash)))
.Returns(1)
.Verifiable();
// invoke service with customer and repoMock.Object here...
repoMock.Verify();
}
}
A slightly better solution would be to turn the SHA1Hasher into an injected service (such as IHasher) so that you can confirm that the PasswordHash property was assigned the value created by the IHasher instance.
Opening op your API even more, you could make the PasswordHash property virtual, so that you could pass a Mock Customer to the AddCustomer method to verify that the property was correctly set.
You could make SHA1Hasher non-static and virtual or wrap it in a ISHA1Hasher interface which can then be mocked. Wrapping static methods and objects in mockable classes is a classic way to increase testability.