Entity framework 如何使用EntityFramework、Repository和Moq对服务进行单元测试?

Entity framework 如何使用EntityFramework、Repository和Moq对服务进行单元测试?,entity-framework,unit-testing,service,moq,Entity Framework,Unit Testing,Service,Moq,我正在从事一个C#项目,该项目使用实体框架、存储库模式、UnitOfWork模式和Moq。 我是EF和Moq单元测试的新手,遇到了以下问题: 当我试图测试服务类中的方法时,我得到了空指针……而且似乎上下文无法实例化。有人能指出我的错误或者给我一个链接吗 例如: portionService.cs /// <summary> /// The PortionService class represents a service for the Portion model. /// <

我正在从事一个C#项目,该项目使用实体框架、存储库模式、UnitOfWork模式和Moq。 我是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();
    }
//
///PortionService类表示部分模型的服务。
/// 
公共类端口服务:服务,IPortionService
{
/// 
///在此构造函数中,调用服务类的基构造函数。
/// 
///表示数据访问层的上下文。
公共端口服务(IDALContext上下文):基(上下文){}
公共无效添加(部分)
{
context.part.Create(部分);
SaveChanges();
}
公共部分GetPortionByName(字符串名称)
{
返回context.partition.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);
    }
//用于PortionService测试的TestClass
[测试类]
公共类端口服务测试
{
专用端口服务PortionService;
//定义模拟对象
私有模拟端口服务模块;
[测试初始化]
公共void Init()
{
_portionService=newportionservice(new-DALContext());
//创建模拟对象
_portionServiceMock=new Mock();
}[测试方法]
public void输入portionNameReturnsPart()
{ 
//安排
//整理数据
部分=新部分{PortionID=12,Name=“testpartition”};
//安排期望
_Setup(service=>service.GetPortionByName(“TestParty”)).Returns(party).Verifiable();
//表演
var result=_portionService.GetPortionByName(“TestParty”);
//核实
Assert.AreEqual(部分、结果、名称);
}
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();
    }
public类DALContext:IDALContext,IDisposable
{
/// 
///_context属性表示当前数据库的上下文。
/// 
私有数据库上下文_上下文;
私有存储库_portionRepository;
...
/// 
///在此构造函数中,DataBaseContext的单个实例被实例化。
/// 
公共上下文()
{
_context=newdatabasecontext();
}

对基于EF的应用程序进行单元测试其实并不容易。我建议使用类似于模拟实体框架的库。

对基于EF的应用程序进行单元测试其实并不容易。我建议使用类似于模拟实体框架的库。

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

下面的示例使用来自的FakeDbSet方法

使用System.Data.Entity;
使用System.Linq;
使用最小起订量;
使用NUnit.Framework;
使用性;
命名空间StackOverflowExample.EntityFramework
{
公共类数据实体
{
公共int Id{get;set;}
公共字符串数据{get;set;}
}
公共接口IContext
{
IDbSet数据实体{get;}
}
公共类数据服务
{
专用IContext数据库;
公共数据服务(IContext上下文)
{
_db=上下文;
}
公共数据实体GetDataById(int id)
{
返回_db.DataEntities.First(d=>d.Id==Id);
}
}
[测试夹具]
公共类数据服务测试
{
[测试]
public void getdatabydtest()
{
//安排
var数据=新的FakeDbSet
{
新数据实体{Id=1,Data=“one”},
新数据实体{Id=2,Data=“two”}
};
var context=newmock();
SetupGet(c=>c.DataEntities).Returns(datas);
var服务=新的数据服务(context.Object);
//表演
var result=service.GetDataById(2);
//断言
结果:满足(r=>
r、 Id==2
&&r.数据=“两”);
}
}
} 

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

下面的示例使用来自的FakeDbSet方法

使用System.Data.Entity;
使用System.Linq;
使用最小起订量;
使用NUnit.Framework;
使用性;
命名空间StackOverflowExample.EntityFramework
{
公共类数据实体
{
公共int Id{get;set;}
公共字符串数据{get;set;}
}
公共接口IContext
{
IDbSet数据实体{get;}
}
公共类数据服务
{
专用IContext数据库;
公共数据服务(IContext上下文)
{
_db=上下文;
}
公共数据实体GetDataById(int id)
{
返回_db.DataEntities.First(d=>d.Id==Id);
}
}
[测试夹具]
公共类数据服务测试
{
[测试]
public void getdatabydtest()
{
//安排
var数据=新的FakeDbSet
{
新数据实体{Id=1,Data=“one”},
新数据实体{Id=2,Data=“two”}
};
var context=newmock();
SetupGet(c=>c.DataEntities).Returns(datas);
var服务=新的数据服务(context.Object);
//表演
var result=service.GetDataById(2);
//断言
结果:满足(r=>
r、 Id==2
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");
        }
    }
}