如何模拟实体框架并在模拟的上下文中获得新的Inserted值



我在嘲笑n层架构中的实体框架。我在试着模仿一个插页。插入是有效的,但当我试图获得插入实体的值时,我无法获得正确的值。

编辑

这是带有变量pat的测试用例。在这种情况下,测试失败是因为关于尝试日期的断言失败。

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));

这是没有变量pat的测试用例。在这种情况下,测试失败(当然),因为我没有嘲笑实体!!!

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());

这里是我想测试的代码:

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();
    ...
}

所以我必须模拟pat变量,即使我在测试中没有使用它!我测试的目的是验证attemptDate的解析是否正确。

问题出在哪里?我想念什么?

谢谢

再次编辑我让你看另一个测试。这个测试有效!在这个测试中,我必须对一个实体进行更新:

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);

正如你所看到的,我用paymentMethod = Easypay创建了billingCenter。。在测试结束时,我做了一个评估,以检查计费中心的支付方式是否在Autopay中发生了变化。但我不会改变测试内部的值!我在facade.UpdateEasyPayFromResultPayment方法中更改了它

以下是您已经发现的的另一个解决方案

//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));

我用这种方法解决了

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));

这里的差异与我的问题相比:

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(x => x.SaveChanges()).Returns(1);

我不喜欢这个解决方案,老实说。。。但它有效!!!我在等更好的东西!感谢

最新更新