Reputation: 2430
I am mocking Entity Framework in a n-layer architecture. I am trying to mock an insert. The insert works, but when I try to get the values of the inserted entity, I cannot get the correct ones.
EDIT
This is the test case with the variable pat
. In this case the test fails because the assert about the attempt date fails.
var mockContext = new Mock<PublicAreaContext>();
//Here I mock the entity I cannot get the correct values
PaymentAttemptTrace pat = new PaymentAttemptTrace();
var mockSetPaymentAttemptTrace = new Mock<DbSet<PaymentAttemptTrace>>();
mockContext.Setup(m => m.Set<PaymentAttemptTrace>()).Returns(mockSetPaymentAttemptTrace.Object);
//Here I create a fake request
TracePaymentAttemptRequest request = new TracePaymentAttemptRequest();
...
//I call the facade. The facade create a PaymentAttemptTrace and insert it in the mocked db
ToolsFacade facade = new ToolsFacade(mockContext.Object);
TracePaymentAttemptResponse response = facade.TraceAutoPayPaymentAttempt(request);
//All asserts are ok, except the last one. The date remain "empty", even if is valorized correctly during the execution of the code (I have checked in debug)
Assert.IsTrue(response.Result == it.MC.WebApi.Models.ResponseDTO.ResponseResult.Success);
mockSetPaymentAttemptTrace.Verify(m => m.Add(It.IsAny<PaymentAttemptTrace>()), Times.Once());
mockContext.Verify(m => m.SaveChanges(), Times.Once());
Assert.IsTrue(pat.AttemptDate == new DateTime(2016, 07, 27, 11, 46, 24));
This is the test case without the variable pat
. In this case the test fails (of course) because I have not mocked the entity!!!
var mockContext = new Mock<PublicAreaContext>();
//Here I create a fake request
TracePaymentAttemptRequest request = new TracePaymentAttemptRequest();
...
//I call the facade. The facade create a PaymentAttemptTrace and insert it in the mocked db
ToolsFacade facade = new ToolsFacade(mockContext.Object);
TracePaymentAttemptResponse response = facade.TraceAutoPayPaymentAttempt(request);
Assert.IsTrue(response.Result == it.MC.WebApi.Models.ResponseDTO.ResponseResult.Success);
mockSetPaymentAttemptTrace.Verify(m => m.Add(It.IsAny<PaymentAttemptTrace>()), Times.Once());
mockContext.Verify(m => m.SaveChanges(), Times.Once());
Here the code I want to test:
public TracePaymentAttemptResponse TraceAutoPayPaymentAttempt(TracePaymentAttemptRequest request)
{
...
DateTime attemptDate = DateTime.Now.Date;
if (!string.IsNullOrWhiteSpace(request.DataTentativoPagamento))
{
try
{
attemptDate = DateTime.ParseExact(request.DataTentativoPagamento, "yyyyMMddTHHmmss", System.Globalization.CultureInfo.InvariantCulture);
}
catch (Exception) { /* Do nothing. attemptDate = DateTime.Now.Date; */ }
}
PaymentAttemptTrace trace = this.CreatePaymentAttemptTraceEntity(/* All data I need to create my entity */);
Repository<PaymentAttemptTrace> repository = new Repository<PaymentAttemptTrace>(base.Context);
repository.Insert(trace); // <- If not mock the entity pat, here go in exception!!
repository.SaveChanges();
...
}
So I have to mock the pat
variable even if I do not use it in the test! The purpose of my test is verify if the parse of the attemptDate is correct.
What can be the problem? What I miss?
Thank you
EDIT AGAIN I let you see another test. This test works! In this test I have to do an update of an entity:
var mockContext = new Mock<PublicAreaContext>() { CallBase = true };
List<BillingCenter> billingCenters = new List<BillingCenter>()
{
new BillingCenter() { Id = "12345600", CustomerId = "123456", PaymentMethod = PaymentMethod.Easypay }
};
var data = billingCenters.AsQueryable();
var mockSet = new Mock<DbSet<T>>();
mockSet.As<IQueryable<T>>().Setup(m => m.Provider).Returns(data.Provider);
mockSet.As<IQueryable<T>>().Setup(m => m.Expression).Returns(data.Expression);
mockSet.As<IQueryable<T>>().Setup(m => m.ElementType).Returns(data.ElementType);
mockSet.As<IQueryable<T>>().Setup(m => m.GetEnumerator()).Returns(data.GetEnumerator());
mockContext.Setup(m => m.Set<BillingCenter>()).Returns(mockSet.Object);
mockContext.Setup(x => x.SaveChanges()).Returns(1);
//Here I create a request
UpdateEasyPayFromResultPaymentRequest request = new UpdateEasyPayFromResultPaymentRequest();
...
PublicAreaFacade facade = new PublicAreaFacade(mockContext.Object);
UpdateEasyPayFromResultPaymentResponse response = facade.UpdateEasyPayFromResultPayment(request);
Assert.IsTrue(billingCenters[0].PaymentMethod == PaymentMethod.Autopay);
As you can see, I create the billingCenter
with paymentMethod = Easypay
.. At the end of the test I do an asserto to check if the payment method of billing center has changed in Autopay
. But I do not change the value inside the test! I change it inside the facade.UpdateEasyPayFromResultPayment
method
Upvotes: 3
Views: 3939
Reputation: 247068
Here is another solution to what you already discovered
//ARRANGE
bool patAdded = false;
PaymentAttemptTrace pat = null; //will assign a value to this when adding new entity
var mockSetPaymentAttemptTrace = new Mock<DbSet<PaymentAttemptTrace>>();
//setup a call back on Add to get the entity that was added to dbset
mockSetPaymentAttemptTrace
.Setup(m => m.Add(It.IsAny<PaymentAttemptTrace>()))
.Callback((PaymentAttemptTrace arg) => {
pat = arg;
padAdded = (pat != null);
});
var mockContext = new Mock<PublicAreaContext>();
mockContext.Setup(m => m.Set<PaymentAttemptTrace>()).Returns(mockSetPaymentAttemptTrace.Object);
mockContext.Setup(x => x.SaveChanges()).Returns(1);//for when you save the added entity
//Here I create a fake request
TracePaymentAttemptRequest request = new TracePaymentAttemptRequest();
...
//I call the facade. The facade create a PaymentAttemptTrace and insert it in the mocked db
ToolsFacade facade = new ToolsFacade(mockContext.Object);
//ACT
TracePaymentAttemptResponse response = facade.TraceAutoPayPaymentAttempt(request);
//ASSERT
Assert.IsTrue(response.Result == it.MC.WebApi.Models.ResponseDTO.ResponseResult.Success);
mockSetPaymentAttemptTrace.Verify(m => m.Add(It.IsAny<PaymentAttemptTrace>()), Times.Once());
mockContext.Verify(m => m.SaveChanges(), Times.Once());
Assert.IsTrue(patAdded);
Assert.IsTrue(pat.AttemptDate == new DateTime(2016, 07, 27, 11, 46, 24));
Upvotes: 3
Reputation: 2430
I have solved in this way
var mockContext = new Mock<PublicAreaContext>();
//Here I mock the entity I cannot get the correct values
List<PaymentAttemptTrace> pat = new List<PaymentAttemptTrace>();
var mockSetPaymentAttemptTrace = new Mock<DbSet<PaymentAttemptTrace>>();
mockSetPaymentAttemptTrace.Setup(m => m.Add(It.IsAny<PaymentAttemptTrace>())).Callback<PaymentAttemptTrace>(list.Add);
mockContext.Setup(m => m.Set<PaymentAttemptTrace>()).Returns(mockSetPaymentAttemptTrace.Object);
mockContext.Setup(x => x.SaveChanges()).Returns(1);
//Here I create a fake request
TracePaymentAttemptRequest request = new TracePaymentAttemptRequest();
...
//I call the facade. The facade create a PaymentAttemptTrace and insert it in the mocked db
ToolsFacade facade = new ToolsFacade(mockContext.Object);
TracePaymentAttemptResponse response = facade.TraceAutoPayPaymentAttempt(request);
//All asserts are ok, except the last one. The date remain "empty", even if is valorized correctly during the execution of the code (I have checked in debug)
Assert.IsTrue(response.Result == it.MC.WebApi.Models.ResponseDTO.ResponseResult.Success);
mockSetPaymentAttemptTrace.Verify(m => m.Add(It.IsAny<PaymentAttemptTrace>()), Times.Once());
mockContext.Verify(m => m.SaveChanges(), Times.Once());
Assert.IsTrue(pat[0].AttemptDate == new DateTime(2016, 07, 27, 11, 46, 24));
Here the differences compare to my question:
List<PaymentAttemptTrace> pat = new List<PaymentAttemptTrace>();
var mockSetPaymentAttemptTrace = new Mock<DbSet<PaymentAttemptTrace>>();
mockSetPaymentAttemptTrace.Setup(m => m.Add(It.IsAny<PaymentAttemptTrace>())).Callback<PaymentAttemptTrace>(list.Add);
And
mockContext.Setup(x => x.SaveChanges()).Returns(1);
I do not like this solution, onestly... but it works!!! I wait for something better! Thank you
Upvotes: 1