I have an N-tier application with Entity Framework (Code-First approach). Now I want to automate some tests. I am using the Moq infrastructure . I find the problem with writing tests. Perhaps my architecture is wrong? With the wrong one, I mean that I wrote components that are not sufficiently isolated, and therefore they are not tested. I don't really like this ... Or maybe I just can't use the moq framework properly.
Let me see my architecture:

At each level, I insert my context into the constructor of the class.
Facade:
public class PublicAreaFacade : IPublicAreaFacade, IDisposable { private UnitOfWork _unitOfWork; public PublicAreaFacade(IDataContext context) { _unitOfWork = new UnitOfWork(context); } }
BLL:
public abstract class BaseManager { protected IDataContext Context; public BaseManager(IDataContext context) { this.Context = context; } }
Repository:
public class Repository<TEntity> where TEntity : class { internal PublicAreaContext _context; internal DbSet<TEntity> _dbSet; public Repository(IDataContext context) { this._context = context as PublicAreaContext; } }
IDataContext is the interface implemented by my DbContext:
public partial class PublicAreaContext : DbContext, IDataContext
Now, how do I layout EF and how do I write tests:
[TestInitialize] public void Init() { this._mockContext = ContextHelper.CreateCompleteContext(); }
Where ContextHelper.CreateCompleteContext() :
public static PublicAreaContext CreateCompleteContext() { //Here I mock my context var mockContext = new Mock<PublicAreaContext>(); //Here I mock my entities List<Customer> customers = new List<Customer>() { new Customer() { Code = "123455" }, //Customer with no invoice new Customer() { Code = "123456" } }; var mockSetCustomer = ContextHelper.SetList(customers); mockContext.Setup(m => m.Set<Customer>()).Returns(mockSetCustomer); ... return mockContext.Object; }
And here is how I write my test:
[TestMethod] public void Success() { #region Arrange PrepareEasyPayPaymentRequest request = new PrepareEasyPayPaymentRequest(); request.CodiceEasyPay = "128855248542874445877"; request.Servizio = "MyService"; #endregion #region Act PublicAreaFacade facade = new PublicAreaFacade(this._mockContext); PrepareEasyPayPaymentResponse response = facade.PrepareEasyPayPayment(request); #endregion #region Assert Assert.IsTrue(response.Result == it.MC.WebApi.Models.ResponseDTO.ResponseResult.Success); #endregion }
It seems that everything is working correctly! And it looks like my architecture is correct. But what if I want to insert / update Entity? Nothing else works! I explain why:
As you can see, I pass the *Request object (this is a DTO) to the facade, and then in my TOA I generate my entity from the correctness of the DTO:
private PaymentAttemptTrace CreatePaymentAttemptTraceEntity(string customerCode, int idInvoice, DateTime paymentDate) { PaymentAttemptTrace trace = new PaymentAttemptTrace(); trace.customerCode = customerCode; trace.InvoiceId = idInvoice; trace.PaymentDate = paymentDate; return trace; }
PaymentAttemptTrace is the Entity that I insert in the Entity Framework. This is not mocking, and I can not enter it. Therefore, even if I pass my mocked context (IDataContext), when I try to insert an object that is not mocking, my test does not work!
This doubt is that my wrong architecture has risen!
So what happened? Architecture or method of using moq? A.
thanks for the help
UPDATE
This is how I check my code. For example, I want to check the payment trace.
Here's the test:
[TestMethod] public void NoPaymentDate() { TracePaymentAttemptRequest request = new TracePaymentAttemptRequest(); request.AliasTerminale = "MyTerminal";
Here is the facade:
public TracePaymentAttemptResponse TracePaymentAttempt(TracePaymentAttemptRequest request) { TracePaymentAttemptResponse response = new TracePaymentAttemptResponse(); try { ... _unitOfWork.PaymentsManager.SavePaymentAttemptResult( easyPay.CustomerCode, request.CodiceTransazione, request.EsitoPagamento + " - " + request.DescrizioneEsitoPagamento, request.Email, request.AliasTerminale, request.NumeroContratto, easyPay.IdInvoice, request.TotalePagamento, paymentDate); _unitOfWork.Commit(); response.Result = ResponseResult.Success; } catch (Exception ex) { response.Result = ResponseResult.Fail; response.ResultMessage = ex.Message; } return response; }
Here is how I developed PaymentsManager :
public PaymentAttemptTrace SavePaymentAttemptResult(string customerCode, string transactionCode, ...) {
In the end, as I wrote the repository:
public class Repository<TEntity> where TEntity : class { internal PublicAreaContext _context; internal DbSet<TEntity> _dbSet; public Repository(IDataContext context) {