【问题标题】:How to UnitTest a Service with EntityFramework, Repository and Moq?如何使用实体框架、存储库和 Moq 对服务进行单元测试?
【发布时间】:2013-05-23 12:48:56
【问题描述】:

我正在开发一个使用 Entity Framework、Repository-Pattern、UnitOfWork-Pattern 和 Moq 的 C# 项目。 我是 EF 和 Moq 单元测试的新手,遇到了以下问题: 当我尝试测试服务类中的方法时,我得到空指针……而且似乎无法实例化上下文。谁能指出我的错误或提供链接?

例子:

portionService.cs

/// <summary>
/// The PortionService class represents a service for the Portion model.
/// </summary>
public class PortionService : Service, IPortionService
{
    /// <summary>
    /// In this constructor the base constructor of the Service class is called.
    /// </summary>
    /// <param name="context">Represents a context of the data access layer.</param>
    public PortionService(IDALContext context) : base(context) { }

    public void Add(Portion portion)
    {
        context.Portion.Create(portion);
        context.SaveChanges();
    }

    public Portion GetPortionByName(string name)
    {
        return context.Portion.GetAll().Where(p => p.Name.ToUpper() == name.ToUpper()).LastOrDefault();
    }

portionServiceTests.cs

// TestClass for PortionService-Tests
[TestClass]
public class PortionServiceTests
{
    private PortionService _portionService;

    // define the mock object
    private Mock<IPortionService> _portionServiceMock;

    [TestInitialize]
    public void Init()
    {
        _portionService = new PortionService(new DALContext());

        // create the mock object
        _portionServiceMock = new Mock<IPortionService>();
    }[TestMethod]
    public void EnteringPortionNameReturnsThePortion()
    { 
    //arrange
    // arrange data
    Portion portion = new Portion { PortionID = 12, Name = "testPortion" };

    //arrange expectations 
    _portionServiceMock.Setup(service => service.GetPortionByName("testPortion")).Returns(portion).Verifiable();

    //act
    var result = _portionService.GetPortionByName("testPortion");

    //verify
    Assert.AreEqual(portion, result.Name);
    }

DALContext.cs

    public class DALContext : IDALContext, IDisposable
{
    /// <summary>
    /// The _context property represents the context to the current Database.
    /// </summary>
    private DatabaseContext _context;

    private Repository<Portion> _portionRepository;
...
    /// <summary>
    /// In this constructor the single instance of the DataBaseContext gets instantiated.
    /// </summary>
    public DALContext()
    {
        _context = new DatabaseContext();
    }

【问题讨论】:

  • 经过几个小时的研究,我找到了 Mr. Mrnka 的this 回答。似乎像我这样的架构中的单元测试服务是无用的,应该包含集成测试。有什么想法吗?
  • 我 100% 同意这位 EF 大师,不要仅仅为了测试而进行测试。如果它不测试实际的正确性,那是毫无价值的。

标签: entity-framework unit-testing service moq


【解决方案1】:

您正在尝试将模拟结果验证为数据库中的实际数据,这就是失败的原因。您的单元测试应该测试服务,并且服务调用上下文,而不是服务本身的模拟。

以下示例使用来自Rowan Miller's article 的 FakeDbSet 方法。

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

namespace StackOverflowExample.EntityFramework
{
    public class DataEntity
    {
        public int Id { get; set; }
        public string Data { get; set; }
    }

    public interface IContext
    {
        IDbSet<DataEntity> DataEntities { get; }
    }

    public class DataService
    {
        private IContext _db;
        public DataService(IContext context)
        {
            _db = context;
        }

        public DataEntity GetDataById(int id)
        {
            return _db.DataEntities.First(d => d.Id == id);
        }
    }

    [TestFixture]
    public class DataServiceTests
    {
        [Test]
        public void GetDataByIdTest()
        {
            //arrange
            var datas = new FakeDbSet<DataEntity>
                {
                    new DataEntity {Id = 1, Data = "one"},
                    new DataEntity {Id = 2, Data = "two"}
                };
            var context = new Mock<IContext>();
            context.SetupGet(c => c.DataEntities).Returns(datas);
            var service = new DataService(context.Object);

            //act
            var result = service.GetDataById(2);

            //assert
            result.Satisfy(r =>
                           r.Id == 2
                           && r.Data == "two");
        }
    }
} 

【讨论】:

  • 那篇博文中有很多优秀的 cmets,我鼓励您通读一遍。
【解决方案2】:

对基于 EF 的应用程序进行单元测试实际上并不容易。我建议使用像 effort 这样的库来模拟实体框架。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-10-19
    • 1970-01-01
    • 2016-09-24
    • 1970-01-01
    • 1970-01-01
    • 2018-03-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多