单元测试在我的模拟数据库中删除一个项目

时间:2018-02-02 10:09:36

标签: c# .net nunit tdd nsubstitute

我正在学习单元测试,并有一个问题。

我用我的数据模拟了我的类ApplicationDbContext。

现在我想从我的数据中删除一个项目。 :(

第一次测试通过,但第二次测试失败,它仍然显示了20个项目

任何人都可以帮助我吗?

我的classe IApplicationDbContext:

    public interface IApplicationDbContext : IDisposable
{
    IDbSet<OrderingEquipment> OrderingEquipments { get; set; }
    int SaveChanges();
    Task<int> SaveChangesAsync();
}

我的classe ApplicationDbContext:

    public class ApplicationDbContext : DbContext, IApplicationDbContext
{
    public virtual IDbSet<OrderingEquipment> OrderingEquipments { get; set; }

    public ApplicationDbContext() : base("DefaultConnection")
    {
    }
}

我的classe OrderingEquipment:

    public class OrderingEquipment
{
    [Key]
    public Guid Guid { get; set; }
    public string Text { get; set; }
    public byte?[] xDEHFile { get; set; }
    public string xDEHFileName { get; set; }
    public DateTime Timestamp { get; set; }

    public string ModelToString()
    {
        return string.Format("Guid: {0}, Text: {1}, xDEHFile: {2}, xDEHFileName: {3} Timestamp: {4}", Guid, Text, xDEHFile, xDEHFileName, Timestamp);
    }
}

My Controller Methode:

public void Remove(OrderingEquipment orderingEquipments)
    {
        if (orderingEquipments == null)
        {
            //throw exception oder ein Result?
            throw new ArgumentNullException("orderingEquipmentsCointener is null");
        }

        try
        {
            using (db)
            {
                //orderingEquipments.ForEach(x => log.Error("Removed: " + x.ModelToString()));
                var itemToRemove = db.OrderingEquipments.Find(orderingEquipments.Guid);
                db.OrderingEquipments.Remove(itemToRemove);
                db.SaveChanges();
            }
        }
        catch (Exception e)
        {
           // orderingEquipments.ForEach(x => log.Error(x.ModelToString(), e));
        }
    }

我的单元测试

public class OrderingEquipmentControllerTests
{

    private IDbSet<OrderingEquipment> dbSet;
    private IApplicationDbContext dbContext;
    private OrderingEquipmentController controller;

    [SetUp]
    public void Initialize()
    {
        // Create test product data
        var orderingEquipments = Builder<OrderingEquipment>.CreateListOfSize(20)
            .All()
            .With(p => p.Guid = Guid.NewGuid())
            .With(p => p.Timestamp = DateTime.UtcNow.AddMonths(new Random().Next(1)))
            .With(p => p.Timestamp = DateTime.UtcNow.AddDays(new Random().Next(2)))
            .TheFirst(5)
            .With(p => p.Text = "First five")
            .Build()
            .AsQueryable();

        dbSet = Substitute.For<IDbSet<OrderingEquipment>>();
        dbSet.Provider.Returns(orderingEquipments.Provider);
        dbSet.Expression.Returns(orderingEquipments.Expression);
        dbSet.ElementType.Returns(orderingEquipments.ElementType);
        dbSet.GetEnumerator().Returns(orderingEquipments.GetEnumerator());
        dbSet.Find(Arg.Any<object[]>()).Returns(callinfo =>
        {
            object[] idValues = callinfo.Arg<object[]>();
            if (idValues != null && idValues.Length == 1)
            {
                Guid requestedId = (Guid)idValues[0];
                return orderingEquipments.FirstOrDefault(p => p.Guid == requestedId);
            }

            return null;
        });

        dbContext = Substitute.For<IApplicationDbContext>();
        dbContext.OrderingEquipments.Returns(dbSet);

        controller = new OrderingEquipmentController(dbContext);
    }

    [Test()]
    public void GetAllOrderingEquipmentsTest()
    {
        var items = controller.GetAllOrderingEquipments();

        Assert.That(items.Count, Is.EqualTo(20));
    }

    [Test()]
    public void RemoveOneOrderingEquipment()
    {
        var items = controller.GetAllOrderingEquipments();
        controller.Remove(items.First());


        Assert.That(items.Count, Is.EqualTo(19));
    }
}

1 个答案:

答案 0 :(得分:0)

模拟的数据库由用于查询的虚假数据存储支持。它实际上并没有保存任何添加到它的东西。您还必须设置模拟在从中删除项目时的假设。

// Create test product data
var orderingEquipments = Builder<OrderingEquipment>.CreateListOfSize(20)
    .All()
    .With(p => p.Guid = Guid.NewGuid())
    .With(p => p.Timestamp = DateTime.UtcNow.AddMonths(new Random().Next(1)))
    .With(p => p.Timestamp = DateTime.UtcNow.AddDays(new Random().Next(2)))
    .TheFirst(5)
    .With(p => p.Text = "First five")
    .Build()
    .ToList();

var queryable = orderingEquipments.AsQueryable();

dbSet = Substitute.For<IDbSet<OrderingEquipment>>();
dbSet.Provider.Returns(queryable.Provider);
dbSet.Expression.Returns(queryable.Expression);
dbSet.ElementType.Returns(queryable.ElementType);
dbSet.GetEnumerator().Returns(queryable.GetEnumerator());
dbSet.Find(Arg.Any<object[]>()).Returns(callinfo => {
    object[] idValues = callinfo.Arg<object[]>();
    if (idValues != null && idValues.Length == 1) {
        Guid requestedId = (Guid)idValues[0];
        return queryable.FirstOrDefault(p => p.Guid == requestedId);
    }
    return null;
});
//Setup remove on db set to remove actual item from fake collection
dbSet.Remove(Arg.Any<OrderingEquipment>())
    .Returns(callInfo => {
        var item = callInfo.Arg<OrderingEquipment>();
        return item != null && orderingEquipments.Remove(item);
    });

这样,模拟的dbSet将知道在要求删除项目时如何表现。测试时模拟使用的任何成员都必须配置为按预期运行。

除此之外,我必须说你不应该嘲笑你不拥有的代码。 DbSet不需要测试。 MS会在发布之前测试它。您也不必直接在控制器中使用它。摘要并将抽象注入控制器。在维护和测试代码时可以提供更大的灵活性。