是否可以使用类为单元测试创​​建虚拟数据?

时间:2013-10-13 05:30:40

标签: c# entity-framework unit-testing

我正在尝试进行一些单元测试,我需要虚拟数据。有些数据我需要具有特定的值,其他的只是随机的。

我的服务层中有一个“CreateProduct”方法,我想知道在我的单元测试中使用这些方法而不是手工制作产品是否是一个好主意。

从表面上看,这似乎是一个好主意,但我担心也许我需要嘲笑或成功通过该方法。

CreateProduct将尝试将产品保存到数据库,但我已经有一个标志可以停止发生保存(用于工作单元件包含回滚)。

我正在使用EF 6-rc1并使用moq模拟DataContext,我将使用AutoFixture,但它不能用于此secnario的盒子,我开始觉得我正在使用太多的新工具曾经如此,也许我现在应该手动完成。

2 个答案:

答案 0 :(得分:1)

如果你想进行单元测试,你只需要测试单元。如果您使用servicelayer中的方法生成一些假数据,则单元测试不仅测试被测单元,还测试服务层中的方法。

所以问题的答案是:不,将服务层用于虚拟数据不是一个好主意

答案 1 :(得分:1)

如果没有代码示例,很难准确说出你在做什么,但我有时会使用IDataSet的{​​{3}}在内存中使用List。典型用法如下:

using System.Data.Entity;
using System.Linq;
using Moq;
using NUnit.Framework;

namespace EFMock
{
    internal interface IDataContext
    {
        IDbSet<DataItem> DataItems { get; set; }
    }

    class DataContext : DbContext, IDataContext
    {
        public IDbSet<DataItem> DataItems{ get; set; }
    }

    class DataItem
    {
        public int SomeNumber { get; set; }
        public string SomeString { get; set; }
    }

    /* ----------- */

    class DataUsage
    {
        public int DoSomething(IDataContext dataContext)
        {
            return dataContext.DataItems.Sum(x => x.SomeNumber);
        }
    }

    /* ----------- */

    [TestFixture]
    class TestClass
    {
        [Test]
        public void SomeTest()
        {
            var fakeDataItems = new [] {
                new DataItem { SomeNumber = 1, SomeString = "One" },
                new DataItem { SomeNumber = 2, SomeString = "Two" }};

            var mockDataContext = new Mock<IDataContext>();
            mockDataContext.SetupGet(x => x.DataItems).Returns(new FakeDbSet<DataItem>(fakeDataItems));

            var dataUsage = new DataUsage();
            var result = dataUsage.DoSomething(mockDataContext.Object);

            Assert.AreEqual(2, result);
        }
    }
}

我还有一个名为“FakeO”的NuGet包,可用于创建一些假对象,其中一些数据是特定值,一些是随机的:

var fakeDataItems = FakeO.Create.Fake<DataItem>(10, // create an IEnumerable of 10 items
    x => x.SomeNumber = FakeO.Number.Next(),        // set to a random number
    x => x.SomeString = "Always This String");      // set to a specific string

对于这种测试要记住的一件事是,对IQueryable使用List将使用Linq2Objects而不是Linq2Entities,因此一些Linq查询的结果将会有所不同。