[英]mocking lambda expressions that are used in methods of the dut
我有一个下面要进行单元测试的方法:
public string GetReferentie(string prefix)
{
IRepositoryAsync<ParameterGetal> parameterGetalRepository = _unitOfWork.RepositoryAsync<ParameterGetal>();
var dateparameterGetal = parameterGetalRepository
.Query(o => o.parameter=="Datum")
.Select()
.Single();
var ordertellerparametergetal = parameterGetalRepository
.Query(o => o.parameter == "orderteller")
.Select()
.Single();
DateTime date = DateTime.Parse(dateparameterGetal.parameterwaarde);
int orderteller=0;
if (date == DateTime.Today)
{
orderteller = int.Parse(ordertellerparametergetal.parameterwaarde);
}
else
{
dateparameterGetal.parameterwaarde = string.Format("{0:dd/MM/yyyy}", DateTime.Today);
orderteller = 0;
}
orderteller++;
ordertellerparametergetal.parameterwaarde = orderteller.ToString();
string result = string.Format("{0}{1:yyyyMMdd}.{2:00}",prefix,DateTime.Today,orderteller);
return result;
}
这里的问题是,我正在使用2个lambda表达式,这使模拟变得很困难,因为我在stackoverflow中找到的大多数解决方案都制定了基于忽略正在使用的lambda的解决方案。
您如何处理? 注意,我有解决方案。 接下来,我将其发布为答案。
有时对于单元测试,必须在DUT的设计中务实,并且可能在类中添加仅用于单元测试的内容。 我从上面修改了该类,以使lambda表达式可变,并允许通过getter访问这些表达式。 这样,单元测试可以访问getter,因此模拟程序可以真正检查要传递的lambda。 这里有足够的谈话是代码:
public class ReferentieBuilder : IReferentieBuilder
{
private readonly IUnitOfWorkAsync _unitOfWork;
private static readonly Expression<Func<ParameterGetal, bool>> _datumExpression = o => o.parameter=="Datum";
private static readonly Expression<Func<ParameterGetal, bool>> _ordertellerExpression = o => o.parameter == "orderteller";
public ReferentieBuilder(IUnitOfWorkAsync unitOfWork)
{
if (unitOfWork == null)
{
throw new ArgumentNullException("unitOfWork");
}
_unitOfWork = unitOfWork;
}
public static Expression<Func<ParameterGetal, bool>> DatumExpression
{
get { return _datumExpression;}
}
public static Expression<Func<ParameterGetal, bool>> OrderTellerExpression
{
get { return _ordertellerExpression; }
}
public string GetReferentie(string prefix)
{
IRepositoryAsync<ParameterGetal> parameterGetalRepository = _unitOfWork.RepositoryAsync<ParameterGetal>();
Debug.Assert(parameterGetalRepository!=null);
var dateparameterGetal = parameterGetalRepository
.Query(DatumExpression)
.Select()
.Single();
var ordertellerparametergetal = parameterGetalRepository
.Query(OrderTellerExpression)
.Select()
.Single();
DateTime date = DateTime.Parse(dateparameterGetal.parameterwaarde);
int orderteller=0;
if (date == DateTime.Today)
{
orderteller = int.Parse(ordertellerparametergetal.parameterwaarde);
}
else
{
dateparameterGetal.parameterwaarde = string.Format("{0:dd/MM/yyyy}", DateTime.Today);
orderteller = 0;
}
orderteller++;
ordertellerparametergetal.parameterwaarde = orderteller.ToString();
string result = string.Format("{0}{1:yyyyMMdd}.{2:00}",prefix,DateTime.Today,orderteller);
return result;
}
}
请参见我已经伪装了两个静态只读成员变量,并预见了静态只读属性。 DatumExpression和OrderTellerExpression。
单元测试代码将变成这样:
[TestFixture]
class ReferentieBuilderTests
{
private IUnitOfWorkAsync _unitOfWork;
[SetUp]
public void setup()
{
List<ParameterGetal> dateParameterGetallen = new List<ParameterGetal>
{
new ParameterGetal{ID = 29, parameter = "Datum", parameterwaarde = string.Format("{0:dd/MM/yyyy}", DateTime.Today.AddDays(-1)) }
};
List<ParameterGetal> tellerParameterGetallen = new List<ParameterGetal>
{
new ParameterGetal{ID = 3, parameter = "orderteller", parameterwaarde = "4" }
};
IQueryFluent<ParameterGetal> datefluent = MockRepository.GenerateStub<IQueryFluent<ParameterGetal>>();
IQueryFluent<ParameterGetal> tellerfluent = MockRepository.GenerateStub<IQueryFluent<ParameterGetal>>();
IRepositoryAsync<ParameterGetal> parametergetalrepository = MockRepository.GenerateStub<IRepositoryAsync<ParameterGetal>>();
_unitOfWork = MockRepository.GenerateStub<IUnitOfWorkAsync>();
_unitOfWork.Stub(u => u.RepositoryAsync<ParameterGetal>())
.Return(parametergetalrepository);
parametergetalrepository.Stub(r => r.Query(ReferentieBuilder.DatumExpression))
.Return(datefluent);
parametergetalrepository.Stub(r => r.Query(ReferentieBuilder.OrderTellerExpression))
.Return(tellerfluent);
datefluent.Stub(q => q.Select())
.Return(dateParameterGetallen);
tellerfluent.Stub(q => q.Select())
.Return(tellerParameterGetallen);
}
[Test]
public void GetFirstReferentieOfDay_returnsCorrectReferentie()
{
ReferentieBuilder referentieBuilder = new ReferentieBuilder(_unitOfWork);
string prefix = "P";
DateTime today = DateTime.Today;
string correctReferentie = string.Format("{0}{1:yyyyMMdd}.01", prefix, today);
Assert.AreEqual(correctReferentie,referentieBuilder.GetReferentie(prefix), "Wrong First Referentie");
}
[Test]
public void GetSecondReferentieOfDay_returnsCorrectReferentie()
{
ReferentieBuilder referentieBuilder = new ReferentieBuilder(_unitOfWork);
string prefix = "P";
referentieBuilder.GetReferentie(prefix);
DateTime today = DateTime.Today;
string correctReferentie = string.Format("{0}{1:yyyyMMdd}.02", prefix, today);
Assert.AreEqual(correctReferentie,referentieBuilder.GetReferentie(prefix), "Wrong Second Referentie");
}
[Test]
public void GetThirdReferentieOfDay_returnsCorrectReferentie()
{
ReferentieBuilder referentieBuilder = new ReferentieBuilder(_unitOfWork);
string prefix = "P";
referentieBuilder.GetReferentie(prefix);
referentieBuilder.GetReferentie(prefix);
DateTime today = DateTime.Today;
string correctReferentie = string.Format("{0}{1:yyyyMMdd}.03", prefix, today);
Assert.AreEqual(correctReferentie, referentieBuilder.GetReferentie(prefix), "Wrong Second Referentie");
}
}
这里的窍门是,该模拟使用的是ReferentieBuilder.DatumExpression和ReferentieBuilder.OrderTellerExpression,而不是在单元测试中以硬编码方式传递相同的lambda表达式。 这具有不重复的额外优点。 通过为允许单元测试访问的lambda表达式添加只读属性,代码并没有那么复杂。
请不要过多地判断代码的逻辑。 它正在尝试生成一个从每天1开始的运行编号。 上次访问该函数的时间以及最后一个数字也存储在数据库中。 这是根据要求,我也不喜欢。
也可以使用Eugene注释以下解决方案:
[TestFixture]
class ReferentieBuilderTests
{
private IUnitOfWorkAsync _unitOfWork;
[SetUp]
public void setup()
{
List<ParameterGetal> dateParameterGetallen = new List<ParameterGetal>
{
new ParameterGetal{ID = 29, parameter = "Datum", parameterwaarde = string.Format("{0:dd/MM/yyyy}", DateTime.Today.AddDays(-1)) }
};
List<ParameterGetal> tellerParameterGetallen = new List<ParameterGetal>
{
new ParameterGetal{ID = 3, parameter = "orderteller", parameterwaarde = "4" }
};
IQueryFluent<ParameterGetal> datefluent = MockRepository.GenerateStub<IQueryFluent<ParameterGetal>>();
IQueryFluent<ParameterGetal> tellerfluent = MockRepository.GenerateStub<IQueryFluent<ParameterGetal>>();
IRepositoryAsync<ParameterGetal> parametergetalrepository = MockRepository.GenerateStub<IRepositoryAsync<ParameterGetal>>();
_unitOfWork = MockRepository.GenerateStub<IUnitOfWorkAsync>();
_unitOfWork.Stub(u => u.RepositoryAsync<ParameterGetal>())
.Return(parametergetalrepository);
parametergetalrepository.Stub(r => r.Query(Arg<Expression<Func<ParameterGetal, bool>>>.Matches(a => LambdaCompare.Eq(a, o => o.parameter == "Datum"))))
.Return(datefluent);
parametergetalrepository.Stub(r => r.Query(Arg<Expression<Func<ParameterGetal, bool>>>.Matches(a => LambdaCompare.Eq(a, o => o.parameter == "orderteller"))))
.Return(tellerfluent);
datefluent.Stub(q => q.Select())
.Return(dateParameterGetallen);
tellerfluent.Stub(q => q.Select())
.Return(tellerParameterGetallen);
}
[Test]
public void GetFirstReferentieOfDay_returnsCorrectReferentie()
{
ReferentieBuilder referentieBuilder = new ReferentieBuilder(_unitOfWork);
string prefix = "P";
DateTime today = DateTime.Today;
string correctReferentie = string.Format("{0}{1:yyyyMMdd}.01", prefix, today);
Assert.AreEqual(correctReferentie,referentieBuilder.GetReferentie(prefix), "Wrong First Referentie");
}
[Test]
public void GetSecondReferentieOfDay_returnsCorrectReferentie()
{
ReferentieBuilder referentieBuilder = new ReferentieBuilder(_unitOfWork);
string prefix = "P";
referentieBuilder.GetReferentie(prefix);
DateTime today = DateTime.Today;
string correctReferentie = string.Format("{0}{1:yyyyMMdd}.02", prefix, today);
Assert.AreEqual(correctReferentie,referentieBuilder.GetReferentie(prefix), "Wrong Second Referentie");
}
[Test]
public void GetThirdReferentieOfDay_returnsCorrectReferentie()
{
ReferentieBuilder referentieBuilder = new ReferentieBuilder(_unitOfWork);
string prefix = "P";
referentieBuilder.GetReferentie(prefix);
referentieBuilder.GetReferentie(prefix);
DateTime today = DateTime.Today;
string correctReferentie = string.Format("{0}{1:yyyyMMdd}.03", prefix, today);
Assert.AreEqual(correctReferentie, referentieBuilder.GetReferentie(prefix), "Wrong Second Referentie");
}
}
可以在这里找到lambda表达式比较器: 测试lambda表达式相等性的最有效方法
使用链接的更新。 使用此解决方案,无需在DUT上进行任何更新,即,无需表达式只读属性。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.