[英]How to mock Entity Framework and get the new Inserted value in the mocked context
I am mocking Entity Framework in a n-layer architecture. 我在n层体系结构中模拟实体框架。 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
. 这是带有变量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
. 这是没有变量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! 因此,即使我没有在测试中使用它,我也必须模拟pat
变量! The purpose of my test is verify if the parse of the attemptDate is correct. 我测试的目的是验证tryDate的解析是否正确。
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
. 正如你所看到的,我创建了billingCenter
与paymentMethod = Easypay
..在测试我做一个asserto检查结账中心的付款方式,改变了结束Autopay
。 But I do not change the value inside the test! 但是我不会在测试中更改值! I change it inside the facade.UpdateEasyPayFromResultPayment
method 我在facade.UpdateEasyPayFromResultPayment
方法中更改了它
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));
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 谢谢
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.