如何使用Entity Framework,Repository和Moq对服务进行单元测试?

时间:2013-05-23 12:48:56

标签: entity-framework unit-testing service moq

我正在开发一个使用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();
    }

2 个答案:

答案 0 :(得分:2)

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

答案 1 :(得分:2)

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

以下示例使用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");
        }
    }
}