Context
I'm writing unit tests for an API I've been developing and I just ran into an issue while trying to UnitTest a "Context" for accessing a MongoDB Storage.
I abstracted the current interface for my context:
public interface IProjectsContext
{
IMongoCollection<Project> Projects { get; }
}
I'm able to successfully use this interface, together with Moq to UnitTest my Repositories.
However, when trying to UnitTest my Context's implementation I've been unable to muster a solution for mocking the inwards:
public class ProjectsContext : IProjectsContext
{
private const string ProjectsCollectionName = "Projects";
private readonly IDatabaseParameters _dbParams;
private readonly MongoClient _client;
private readonly IMongoDatabase _database;
private IMongoCollection<Project> _projects;
public ProjectsContext(IDatabaseParameters dbParams)
{
_dbParams = dbParams ?? throw new ArgumentNullException(nameof(dbParams));
_client = new MongoClient(_dbParams.ConnectionString);
_database = _client.GetDatabase(_dbParams.DatabaseName);
}
public IMongoCollection<Project> Projects
{
get
{
if (_projects is null)
_projects = _database.GetCollection<Project>(ProjectsCollectionName);
return _projects;
}
}
}
The unit test in question is:
private readonly Fixture _fixture = new Fixture();
private readonly Mock<IDatabaseParameters> _dbParametersMock = new Mock<IDatabaseParameters>();
public ProjectsContextTests()
{
}
[Fact(DisplayName = "Create a Project Context")]
public void CreateProjectContext()
{
// Arrange
_dbParametersMock.Setup(m => m.ConnectionString).Returns(_fixture.Create<string>());
_dbParametersMock.Setup(m => m.DatabaseName).Returns(_fixture.Create<string>());
// Act
var result = new ProjectsContext(_dbParametersMock.Object);
// Assert
result.Should().NotBeNull();
result.Should().BeAssignableTo<IProjectsContext>();
// TODO: Write a test to assert the ProjectCollection
}
Question
The only solution I can think of is changing my ProjectsContext to have a constructor with receives, as a parameter, the IMongoDatabase which is going to be used. However, is this the only solution?
Libraries used
I'm using the following NuGets for my UnitTests and Implementation:
xUnit
Coverlet.msbuild
Moq
AutoFixture
FluentAssertions
MongoDB
ProjectsContext is tightly coupled to implementation concerns/details (ie: MongoClient) that make testing it isolation difficult.
IMongoDatabase is the true dependency and should be explicitly injected into the target class.
Reference Explicit Dependencies Principle
public class ProjectsContext : IProjectsContext {
private const string ProjectsCollectionName = "Projects";
private readonly IMongoDatabase database;
private IMongoCollection<Project> projects;
public ProjectsContext(IMongoDatabase database) {
this.database = database;
}
public IMongoCollection<Project> Projects {
get {
if (projects is null)
projects = database.GetCollection<Project>(ProjectsCollectionName);
return projects;
}
}
}
As for the creation/initialization of the database, that implementation detail can be moved to the composition root
//...ConfigureServices
services.AddScoped<IMongoDatabase>(sp => {
var dbParams = sp.GetRequiredService<IDatabaseParameters>();
var client = new MongoClient(dbParams.ConnectionString);
return client.GetDatabase(dbParams.DatabaseName);
});
//...
Testing of the target class can now be done in isolation without unexpected behavior from 3rd party implementation concerns
[Fact(DisplayName = "Create a Project Context")]
public void CreateProjectContext() {
// Arrange
var collectionMock = Mock.Of<IMongoCollection<Project>>();
var dbMock = new Mock<IMongoDatabase>();
dbMock.Setup(_ => _.GetCollection<Project>(It.IsAny<string>()))
.Returns(collectionMock);
// Act
var result = new ProjectsContext(dbMock.Object);
// Assert
result.Should().NotBeNull()
.And.BeAssignableTo<IProjectsContext>();
//Write a test to assert the ProjectCollection
result.Projects.Should().Be(collectionMock);
}
Related
I have a class that I am trying to test out through writing some unit test in C#. I am also using Moq library in my unit test for mocking.
Below are some of the methods in my class which I want to mock so that they can return some dummy data which I want to return always.
public class DataManager
{
public DataManager(ILoggingService loggingService, IConfiguration configuration)
{
// ...
}
// how to mock this to return dummy data?
private DataHolder GetData()
{
//... return DataHolder object
}
// how to mock this to return dummy data?
private IEnumerable<ProcessClient> GetClientValues(string value)
{
//... return IEnumerable<ProcessClient> object
}
}
This is how I am testing it out:
private Mock<ClientUtility> utility;
[SetUp]
public void Setup()
{
utility = new Mock<ClientUtility>();
}
[Test]
public void Test1()
{
// what should I do here so that "GetData" and "GetClientValues" return dummy data when I call below class constructor?
var testName = "config1";
var testContent = "{}";
utility.Setup(x => x.Add(new DataStatus { Pin = "test" }, "data.com", "test")).Returns(Task.FromResult(true));
var dataManager = new DataManager(loggingService.Object, configuration.Object);
Assert.AreEqual(testContent, dataManager.GetStuff(testName)[0]);
}
Question:
How can I mock "GetData" and "GetClientValues" using Moq or any other library to return dummy data from those two methods? Is this possible to do?
I think you can use CallBase = true.
So your mock will behave like true class.
var dataManager = new Mock<DataManager>(loggingService.Object, configuration.Object) { CallBase = true };
dataManager.Object.Method1();
dataManager.Object.Method2();
And you can mock some methods like you do with utility.
Search by "CallBase" on page:
https://github.com/Moq/moq4/wiki/Quickstart
UPDATE
I made methods public to call them.
And there is some issue, that i didn't see last time. You need to make "virtual" methods if you want change their behavior.
There is example of code. As you can see, GetClientValues() returns real data because we call default real implementation with CallBase = true and GetData() returns dummy data because we mocked its behavior.
public class DataManager
{
public DataManager(ILoggingService loggingService, IConfiguration configuration)
{
// ...
}
// how to mock this to return dummy data?
public virtual DataHolder GetData()
{
return new DataHolder
{
Data = "RealData"
};
}
// how to mock this to return dummy data?
public IEnumerable<ProcessClient> GetClientValues(string value)
{
return new List<ProcessClient>
{
new ProcessClient
{
Data = "RealData"
}
};
}
}
And tests.
public class Tests
{
[SetUp]
public void Setup()
{
}
[Test]
public void Test1()
{
var loggingService = new Mock<ILoggingService>();
var config = new Mock<IConfiguration>();
var dataManager = new Mock<DataManager>(loggingService.Object, config.Object){CallBase = true};
dataManager.Setup(x => x.GetData()).Returns(new DataHolder { Data = "FakeData" });
Assert.AreEqual("RealData", dataManager.Object.GetClientValues("test").First().Data);
Assert.AreEqual("FakeData", dataManager.Object.GetData().Data);
}
}
But anyway i think, that this approach isn't good for testing.
There is a problem with testing private methods. We have some ways (for example Invoke()), but in general, "if you want to unit test a private method, something may be wrong". I would like to recommend you to read something about test design and writing testable code.
About testing private methods How do you unit test private methods?.
I'm moving first steps in TDD (I'm studying "Professional Test-Driven Development with C#" by Bender and McWherter).
I'm trying to write my first application with TDD: I assume to have a DataService class for manage persistence. I wrote two tests that pass, but I think I've not got the point.
This is my first test, I assume that I can instantiate a Transaction, whatever it means in the DataService
public void Begin_a_transaction_should_returns_true_when_is_all_ok()
{
Mock<IDataLayer> dataLayer = new Mock<IDataLayer>();
DataService sut = new DataService(dataLayer.Object);
bool expected = true;
dataLayer.Setup(dl => dl.BeginTransaction()).Returns(expected);
bool actual = sut.BeginTransaction();
Assert.AreEqual(expected, actual);
}
According to TDD now I wrote the classes, no issues with this
public class DataService
{
private IDataLayer _dataLayer;
public DataService(IDataLayer dataLayer)
{
this._dataLayer = dataLayer;
}
public bool BeginTransaction()
{
return _dataLayer.BeginTransaction();
}
}
Now I want to write second test: BeginTransaction should fail if transaction already exists, and I demand this to IDataLayer
[Test]
public void Begin_a_transaction_should_throws_exception_if_transaction_already_exists()
{
Mock<IDataLayer> dataLayer = new Mock<IDataLayer>();
DataService sut = new DataService(dataLayer.Object);
dataLayer.Setup(dl => dl.BeginTransaction()).Throws(new Exception("Transaction already exists"));
Assert.Throws<Exception>(() => sut.BeginTransaction());
}
And now the point: tests pass without writing any line of code, because I've mocked the BeginTransaction to throw an Exception.
That can be OK because I'll test it in the implementation of IDataLayer tests, but if I mock all, DataService tests are useful?
I would say this happens because you're testing the behavior of a class that does not have any behavior other than wrapping the IDataLayer - anything that happens in the wrapped class is simply passed on to the outside. The same thing that you are describing happens for the case when the method returns true although it's less obvious.
To make your example more meaningful you could add some behavior that is dependent on the result of IDataLayer's BeginTransaction(), like;
Implementation
public class DataService
{
public DataService(IDataLayer dataLayer, IBookRepository bookRepository)
{
_dataLayer = dataLayer;
_bookRepository = bookRepository;
}
public void StoreBookInfo(string data)
{
if (_dataLayer.BeginTransaction())
_bookRepository.StoreBookInfo(data);
else
throw new SomeException();
}
}
Test
[Test]
public void Should_store_book_info_if_transaction_can_be_started()
{
Mock<IDataLayer> dataLayer = new Mock<IDataLayer>();
Mock<IBookRepository> bookRepository = new Mock<IBookRepository>();
dataLayer.Setup(dl => dl.BeginTransaction()).Returns(true);
bookRepository.Setup(x => x.StoreBookInfo(It.IsAny<string>()));
DataService sut = new DataService(dataLayer.Object, bookRepository.Object);
sut.StoreBookInfo("SomeValue");
bookRepository.Verify(x => x.StoreBookInfo(It.IsAny<string>()));
}
[Test]
public void Should_throw_exception_if_transaction_cannot_be_started()
{
Mock<IDataLayer> dataLayer = new Mock<IDataLayer>();
Mock<IBookRepository> bookRepository = new Mock<IBookRepository>();
dataLayer.Setup(dl => dl.BeginTransaction()).Returns(false);
DataService sut = new DataService(dataLayer.Object, bookRepository.Object);
Assert.Throws<SomeException>(() => sut.StoreBookInfo("someValue"));
}
Exposing internals just for the sake of tests generally is not good practice. In your case _transaction is made protected so that decorator could do changes to it's internal state. I'd better suggest to mimic behavior of a client.
[Test]
public void Begin_a_transaction_should_throws_exception_if_transaction_already_exists()
{
Mock<IDataLayer> dataLayer = new Mock<IDataLayer>();
DataService sut = new DataService(dataLayer.Object);
sut.BeginTransaction();
Assert.Throws<Exception>(() => sut.BeginTransaction());
}
Well, I reviewed my code in this way.
public class DataService
{
private IDataLayer _dataLayer;
protected object _transaction;
public DataService(IDataLayer dataLayer)
{
this._dataLayer = dataLayer;
}
public bool BeginTransaction()
{
if (_transaction != null)
throw new Exception("Transaction already exists");
_transaction = _dataLayer.BeginTransaction();
return true;
}
}
Than I use a decorator pattern in test class
internal class DataServiceDecorator : DataService
{
public DataServiceDecorator(IDataLayer dataLayer) : base(dataLayer)
{ }
public void InjectTransactionObject(object transaction)
{
this._transaction = transaction;
}
}
So I'm able to write this test
[Test]
public void Begin_a_transaction_should_throws_exception_if_transaction_already_exists()
{
Mock<IDataLayer> dataLayer = new Mock<IDataLayer>();
DataServiceDecorator sut = new DataServiceDecorator(dataLayer.Object);
sut.InjectTransactionObject(new object());
Assert.Throws<Exception>(() => sut.BeginTransaction());
}
What do you think about this?
I have recently built a quiz application for Xamarin.Android, and want to dome some Unit Testing on the shared library.
I am using a repository pattern with the following files.
SQLiteMyAppRepository.cs
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using SQLite;
namespace MyApp.DataLayer
{
public class MyAppRepository : IMyAppRepository
{
public static string DatabaseName = "MyApp.sqlite";
private SQLiteConnection _dbConnection;
public MyAppRepository()
{
string docFolder = Environment.GetFolderPath(Environment.SpecialFolder.Personal);
string dbFilePath = Path.Combine(docFolder, DatabaseName);
_dbConnection = new SQLiteConnection(dbFilePath);
}
I have then created a new project to test some of these elements.
The primary issue I am having, is that when I try and run the test, I am getting the following exception:
MyApp.Tests.RepositoryTests.AddQuestion threw
exception:
SQLite.SQLiteException: no such table: Questions
I have been messing about with it for a few hours now and can't seem to find what is wrong, any help would be appreciated. I thought Mocking the repository would get around any issues like this.
The problem here is that you are trying to use a real database in the context of unit tests. One possible solution could be to introduce an additional level of abstraction and separate repository from context(database). This could enable you to properly mock dependencies, e.g.
public interface IMyAppContext
{
IList<Question> GetAllQuestions();
int AddQuestion(Question question);
int UpdateQuestion(Question question);
int DeleteQuestion(Question question);
}
where implementation could be something like this:
public class MyAppContext : IMyAppContext
{
private readonly string _databaseName = "MyApp.sqlite";
private readonly SQLiteConnection _dbConnection;
public MyAppContext()
{
string docFolder = Environment.GetFolderPath(Environment.SpecialFolder.Personal);
string dbFilePath = Path.Combine(docFolder, DatabaseName);
_dbConnection = new SQLiteConnection(dbFilePath);
}
public int AddQuestion(Question question)
{
return _dbConnection.Insert(question);
}
...
}
then inject this one to the repository...
public class MyAppRepository : IMyAppRepository
{
private readonly IMyAppContext _context;
public MyAppRepository(IMyAppContext context)
{
_context = context;
}
public int AddQuestion(Question question)
{
return _context.Insert(question);
}
...
}
Now, after you have done this setup of the unit test should be for example,
[TestMethod]
public void AddQuestion()
{
// Arrange
var contextMock = new Mock<IMyAppContext>();
contextMock.Setup(r => r.AddQuestion(It.IsAny<Question>())).Returns(1);
var sut = new SqLiteAbcdRepository(contextMock.Object);
// Act
var id = sut.AddQuestion(new Question());
// Assert
Assert.AreEqual(1, id);
}
I am new to write Unit Tests. Therefore, I have been struggling with.
I need to insert product via an external WebService. Then the WebService will return a string that is necessary to update the product afterwards.
This is my ApiController:
public class ProductController : ApiController
{
private IProductRepository _ProductRepository;
private IWebService _WebService;
public ProductController(IProductRepository productRepository, IWebService webService)
{
_ProductRepository = productRepository;
_WebService = webService;
}
public HttpResponseMessage Add(string title)
{
using (TransactionScope scope = new TransactionScope())
{
Product product = new Product
{
Title = title
};
this._ProductRepository.Add(product);
// WebService will return a string
string result = this._WebService.Add(product.ID, DateTime.Now);
product.ServiceResult = result;
this._ProductRepository.Update(product);
scope.Complete();
}
return Request.CreateResponse(HttpStatusCode.Created);
}
}
I was wondering how should I write a unit test for this code?
I've tried to write it as follows: (with NUnit, Moq)
[TestFixture]
public class ProductControllerShould : AssertionHelper
{
private Mock<IWebService> _WebService;
private Mock<IProductRepository> _ProductRepository;
[SetUp]
public void Setup()
{
_WebService = new Mock<IWebService>();
_ProductRepository = new Mock<IProductRepository>();
}
[Test]
public void ReturnCreatedOnAdd()
{
_WebService.Setup(b => b.Add(1, DateTime.Now))
.Returns("0");
var controller = new ProductController(_ProductRepository.Object,
_WebService.Object);
var result = controller.Add("Lumia");
Expect(result, Is.EqualTo(HttpStatusCode.Created));
}
}
but when I debug the test, result in this line is null that is not correct.
string result = this._WebService.Add(product.ID, DateTime.Now);
Shouldn't this line handle the behaviour of _WebService.Add() and return "0"?
_WebService.Setup(b => b.Add(1, DateTime.Now))
.Returns("0");
I know I write the test incorrectly but I don't know what should I do.
Thanks.
The problem here, is that you are mocking call of static method `DateTime.Now' . But "Now" in the time point of mocking and as it is called are different. Therefore your call doesn't return anything.
I could suggest 3 following ways:
1) It doesn't really matter for you, if the call was with DateTime.Now or not, in that case you could ignore the second argument:
_WebService.Setup(b => b.Add(1, It.IsAny<DateTime>())).Returns("0");
2) You want to test, that the call was with DateTime.Now. In that case i create an interface for getting DateTime.Now:
public interface IDateTimeNowProvider
{
DateTime Now { get; }
}
public ProductController(IProductRepository productRepository,
IWebService webService,
IDateTimeNowProvider dateTimeNowProvider)
{
_ProductRepository = productRepository;
_WebService = webService;
_dateTimeNowProvider = dateTimeNowProvider;
}
In production code you use default implementation of it, that just returns DateTime.Now. But in your test class you do mock this interface with some predefined values and you test for using this value.
var now = DateTime.Parse("2017-01-22");
var _dateTimeNowProvider = new Mock<IDateTimeNowProvider>();
var controller = new ProductController(_ProductRepository.Object,
_WebService.Object, _dateTimeNowProvider.Object );
_dateTimeNowProvider.Setup(x => x.Now).Returns(now);
_WebService.Setup(b => b.Add(1,now)).Returns("0");
3) You could use special mocking framework that allows to mock static methods, as for example typemock isolator
I have added a unit test to a mvc5 application manually.
This is my business logic
public void AddTreatments(TreatmentView model)
{
using(var treatment = new TreatmentRepository())
{
var treat = new PhysiqueData.ModelClasses.Treatment()
{
treatmentID = model.treatmentID,
treatmentCost = model.treatmentCost,
treatmentDuration = model.treatmentDuration,
treatmentName = model.treatmentName
}
treatment.Insert(treat);
}
}
This is my repository used in the service layer
public class TreatmentRepository:ITreatmentRepository
{
private ApplicationDbContext _datacontext;
private readonly IRepository<Treatment> _treatmentRepository;
public TreatmentRepository()
{
_datacontext = new ApplicationDbContext();
_treatmentRepository = new RepositoryService<Treatment>(_datacontext);
}
public void Insert(Treatment model)
{
_treatmentRepository.Insert(model);
}
}
The next code is my actual unit test for my treatment and it is not working,
please can I get some guidance on it. I googled a lot of things and still can't get it right.
[TestClass]
public class UnitTest1
{
[TestMethod]
public void AddingTreatmenttodatabase()
{
//var business = new TreatmentBusiness(new TreatmentRepository());
var treatment = new Treatment()
{
treatmentID = 1,
treatmentCost = 250,
treatmentDuration = 45,
treatmentName = "LowerBack"
};
var repositoryMock = new Mock<ITreatmentRepository>();
repositoryMock.Setup(x => x.Insert(treatment));
var business = new TreatmentBusiness(repositoryMock.Object);
business.AddTreatments(treatment);
repositoryMock.Verify(x => x.Insert(treatment), Times.Once());
}
}
So you're instantiating a mock of ITreatmentRepository, setting up some behaviour and injecting it into your TreatmentBusiness class. So far, so good.
But then, in your AddTreatments method, you're instantiating a new TreatmentRepository, instead of using the one injected in via the constructor.
I'm assuming your constructor looks something like this:
public class TreatmentBusiness
{
private readonly ITreatmentRepository repository;
public TreatmentBusiness(ITreatmentRepository repository)
{
this.repository = repository;
}
...
}
In which case, your method should look like this:
public void AddTreatments(TreatmentView model)
{
using (var treatment= this.repository)
{
var treat = new PhysiqueData.ModelClasses.Treatment();
{
treat.treatmentID = model.treatmentID;
treat.treatmentCost = model.treatmentCost;
treat.treatmentDuration = model.treatmentDuration;
treat.treatmentName = model.treatmentName;
}
treatment.Insert(treat);
}
}
Notice the usage of the field repository, as opposed to instantiating a new one.
As per Jimmy_keen's suggestion, in order to ensure your repository is properly instantiated and accessible throughout your class, a factory is advisable.
There are several ways you can achieve a repository factory, either you hand crank a dedicated factory and inject that into your constructor, like so:
public class TreatmentBusiness
{
private readonly ITreatmentRepositoryFactory repositoryFactory;
public TreatmentBusiness(ITreatmentRepositoryFactory repositoryFactory)
{
this.repositoryFactory = repositoryFactory;
}
...
}
And that change the way you access your repository like so:
public void AddTreatments(TreatmentView model)
{
using (var treatment= this.repositoryFactory.Make())
//or whatever method name you've chosen on your factory
If you feel this is too heavy handed, you can opt for a method delegate (Func<>) and inject just a method that instantiates a new TreatmentRepository.
This would change your constructor like so:
public class TreatmentBusiness
{
private readonly Func<TreatmentRepository> getTreatmentRepository;
public TreatmentBusiness(Func<TreatmentRepository> getTreatmentRepository)
{
this.getTreatmentRepository = getTreatmentRepository;
}
....
}
And you would change your method like this:
public void AddTreatments(string model)
{
using (var treatment = this.getTreatmentRepository()) //Or this.getTreatmentRepository.Invoke() - same thing
{
...
}
}
The way you resolve that dependency is up to you, either do it manually and inject that delegate like this when instantiating your Business object:
var treatmentBusiness = new TreatmentBusiness(() => new TreatmentRepository());
or you can use one of the many IoC containers/DI frameworks out there.