简体   繁体   English

如何模拟实体框架并在模拟的上下文中获取新的插入值

[英]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 . 正如你所看到的,我创建了billingCenterpaymentMethod = 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM