我编写了一个使用DbContext.Database.SqlQuery()(EF6.1)从数据库获取数据的方法:
internal List<WorkOrderLine> Get()
{
var sql = GetSql();
var workOrders = Context.Database.SqlQuery<Model.Analysis.WorkOrder>(sql).ToList();
return workOrders.Select(workOrder => new WorkOrderLine
{
Id = workOrder.a,
Title = workOrder.b,
Status = workOrder.c,
Location = workOrder.d,
AssignedTo = workOrder.e,
StartDate = workOrder.f,
DueDate = workOrder.g,
CompletedDate = h
}).ToList();
}
我想为该方法编写一个单元测试,并检查预期的SQL是否已传递到SQLQuery,然后传回一个数据列表,以便可以通过方法的其余部分对其进行处理,以便我可以检查输出
我相信正确/最好的方法是模拟DbContext并将这个模拟的上下文传递给类而不是真实的上下文。如果是这样,我想我可以通过以下方式之一做到这一点:
使用Moq
手动创建模拟以执行测试并返回数据
使用模拟技术是正确的吗?
如果是这样,这两个选项中哪一个最简单/最好?
P.S。我在使用EF进行测试时通常会使用Effort,但它不会处理此方法。
编辑:
这是完整的课程:
internal Report(MyContext context, ChartWidgetFilter filters, string ownerEntityFilter)
: base(context, filters, ownerEntityFilter)
{
}
internal List<WorkOrderLine> Get()
{
var sql = GetSql();
var workOrders = Context.Database.SqlQuery<Model.Analysis.WorkOrder>(sql).ToList();
return workOrders.Select(workOrder => new WorkOrderLine
{
Id = workOrder.a,
Title = workOrder.b,
Status = workOrder.c,
Location = workOrder.d,
AssignedTo = workOrder.e,
StartDate = workOrder.f,
DueDate = workOrder.g,
CompletedDate = h
}).ToList();
}
private string GetSql()
{
//return the sql generated using the filters and ownerEntityFilter
//parameters passed into the constructor
}
}
编辑2:
我需要测试的两件事是:
GetSql()为传递给构造函数的参数创建正确的SQL - ChartWidgetFilter filters, string ownerEntityFilter
return workOrders.Select...
语句为WorkOrderLine
个对象列表返回正确映射的Model.Analysis.WorkOrder
个对象列表
答案 0 :(得分:0)
以下是关于如何“模拟”单元测试的示例
public class SolvencyBllTest
{
private MyAttBLL myAttBll;
private readonly List<AttestationEntity> attestationsFakeForTest = new List<AttestationEntity>
{
/// ... Build the child object , used for 'mock'
}
//Initialize event => here we define what the 'mock' should to de when we use the [GetListWithChildren] function
[TestInitialize]
public void Setup()
{
var mockedAttestationFakeToTest = new Mock<IAttestationDataAccessLayer>();
//setup GetAll : return the whole list
mockedAttestationFakeToTest
.Setup(attestation => attestation.GetListWithChildren(It.IsAny<Expression<Func<AttestationEntity, bool>>>()))
.Returns((Expression<Func<AttestationEntity, bool>> expression) =>
{
return this.attestationsFakeForTest.AsQueryable().Where(expression);
});
this.myAttBll = new MyAttBLL(attestationsCertificatesRefundDal: null, attestationDal: mockedAttestationFakeToTest.Object, emailNotifier: mockedEmailNotifier.Object);
}
[TestMethod]
public void SolvencyBllTest_CheckAttestation()
{
// Initalize the result
SolvencyCheckResult solvencyCheckResult = new SolvencyCheckResult()
{
solvency = new SolvencyModel()
};
// Declare and initializes our object which encapsulates our parameters for the solvency check
SolvencyCheckParameters solvencyCheckParams = new SolvencyCheckParameters(TestConstants.Contact.LAST_NAME, TestConstants.Contact.FIRST_NAME, TestConstants.Contact.BIRTH_DATE, TestConstants.Address.STREET, TestConstants.Address.ZIPCODE, TestConstants.UNIT_TEST_USER);
// this (solvencyBll) will not try to find in the database but in the collection with just mock before
// Try to retrieve all certificates dating back 3 months and have the same name + first name + date of birth
List<AttestationModel> attsLatestToCheck = this.myAttBll.CheckLatestAttestation(solvencyCheckResult, solvencyCheckParams);
// 1 attestation created today => OK
// 1 attestation created 1 month ago => OK
// 1 attestation created 2 month ago => OK
// 1 attestation created 4 month ago => KO
Assert.AreEqual(3, attsLatestToCheck.Count);
}
使用BLL部分函数中的dbContext的示例
public IEnumerable<AttestationEntity> GetListWithChildren(Expression<Func<AttestationEntity, bool>> pred)
{
using (ScDbContext context = new ScDbContext())
{
return this.GetListWithChildrenInternal(context, pred).OrderBy(att => att.CreatedDate).ToList();
}
}
internal IEnumerable<AttestationEntity> GetListWithChildrenInternal(ScDbContext context, Expression<Func<AttestationEntity, bool>> pred)
{
return this.GetListInternal(context, pred, attestationChildren).OrderBy(att => att.CreatedDate).ToList();
}
internal IEnumerable<E> GetListInternal(DBC context, Expression<Func<E, bool>> where, params Expression<Func<E, object>>[] navigationProperties)
{
IQueryable<E> dbQuery = context.Set<E>();
//Apply eager loading
foreach (Expression<Func<E, object>> navigationProperty in navigationProperties)
dbQuery = dbQuery.Include<E, object>(navigationProperty);
return dbQuery
//.AsNoTracking() //Don't track any changes for the selected item
.Where(where)
.ToList(); //Apply where clause
}