UnitTest中的FakeIseasy Action参数,但仍执行内部Action代码
本文关键字:Action 执行 内部 代码 中的 FakeIseasy 参数 UnitTest | 更新日期: 2023-09-27 18:26:13
我目前正在为我添加到ASP.NET项目中的一些新功能进行一些UnitTest(不,这不是测试驱动设计)。我们使用NHibernate框架,并使用UnitTest模拟库FakeItEasy
。
我有以下课程&我想测试的方法:
public class Round
{
public static Round Create(List<Company> activeCompanies, Period period,
BusinessUser user, BusinessUser systemUser,
ISession session, IEntityQuery entityQuery,
RoundProcessBuilder processBuilder)
{
var round = new Round
{
Processes = new List<Process>();
Period = period,
CreationDate = DateTime.Now,
CreatedBy = user
};
// Save the Round in the DB so we can use it's Id in the Processes:
session.Save(round);
foreach (var company in activeCompanies)
{
var companyData = session.Get<CompanyData>(company.Id);
var processResult =
roundProcessBuilder.Build(
systemUser,
new CreateRoundProcessData(company, round, companyData),
entityQuery,
session);
processResult.HandleProcess(process =>
{
// serviceBus can stay null
process.Create(systemUser, DateTime.Now, session, null);
// No need to save the session here. If something went
// wrong we don't want halve of the processes being saved
round.Processes.Add(process);
// It's all or nothing
});
}
return round;
}
}
我主要想测试的是:当我对100个活跃的公司使用Round#Create
方法时,它应该创建100个流程,每个流程都应该包含RoundId
。
这是我迄今为止的UnitTest:
[TestFixture]
public class RoundTest
{
private BusinessUser _systemUser;
private DateTime _creationDateRound1;
private List<Company> _activeCompanies;
private RoundProcessBuilder _roundProcessBuilder;
private ISession _session;
[SetUp]
public void Setup()
{
_creationDateRound1 = new DateTime(2015, 10, 5);
_systemUser = TestHelper.CreateBusinessUser(Role.Create("systemuser", "test",
Int32.MaxValue));
_activeCompanies = new List<Company>
{
TestHelper.CreateCompany();
};
_roundProcessBuilder = A.Fake<RoundProcessBuilder>();
_session = A.Fake<ISession>();
}
[Test]
public void TestCreateRoundWithoutPreviousRound()
{
var fakeExpectedRound = Round.Create(_activeCompanies, DateTime.Now.ToPeriod(),
_systemUser, _systemUser, _session, null, _roundProcessBuilder);
var fakeExpectedRoundData = RoundProcessData.Create(TestHelper.CreateCompany(),
fakeExpectedRound, new CompanyData());
var fakeExpectedProcess = new Process(_systemUser, null, "processName", null,
fakeExpectedRoundData, "controllerName", null);
var processSuccessResult = new ProcessSuccessResult(fakeExpectedProcess);
A.CallTo(() => _roundProcessBuilder.Build(null, null, null, null))
.WithAnyArguments()
.Returns(processSuccessResult);
A.CallTo(() => processSuccessResult.HandleProcess(A<Action<Process>>.Ignored))
.Invokes((Action<Process> action) => action(fakeExpectedProcess));
var round = Round.Create(_activeCompanies, _ceationDateRound1.ToPeriod(),
_systemUser, _systemUser, _session, null, _roundProcessBuilder);
Assert.AreEqual(_activeCompanies.Count, round.Processes.Count, "Number of processes");
Assert.AreEqual(round.Period.Quarter, Math.Ceiling(_creationDateRound1.Month / 3.0m), "Quarter");
Assert.AreEqual(round.Period.Year, round.Year, "Year");
// Test if each of the processes knows the RoundId, have the proper state,
// and are assigned to the systemuser
//foreach (var process in round.Processes)
//{
// var roundProcessData = process.ProcessData as RoundProcessData;
// Assert.IsNotNull(roundProcessData, "All processes should have RoundProcessData-objects as their data-object");
// Assert.AreEqual(roundProcessData.Round.Id, round.Id, "RoundId");
// Assert.AreEqual(process.Phase.State, PhaseState.Start, "Process state should be Start");
// Assert.AreEqual(process.AssignedTo, _systemUser, "AssignedTo should be systemuser");
//}
}
... // More tests
}
我的问题在于以下代码:
A.CallTo(() => processSuccessResult.HandleProcess(A<Action<Process>>.Ignored))
.Invokes((Action<Process> action) => action(fakeExpectedProcess));
它给出一个"The specified object is not recognized as a fake object.
"错误。
我之所以有这部分代码,是因为以下部分中的process
在没有它的情况下为空:
processResult.HandleProcess(process => // <- this was null
{
process.Create(systemUser, DateTime.Now, session, null);
round.Processes.Add(process);
});
PS:我在UnitTest中用额外的检查取消了foreach的注释,因为当我模拟process
本身时,它很可能毫无用处。。我的主要测试是,是否根据给定的活跃公司创建流程并将其添加到列表中。
您的问题似乎是试图将"fake"逻辑添加到一个实际上不是假的对象:
// You create this as an instance of ProcessSuccessResult:
var processSuccessResult = new ProcessSuccessResult(fakeExpectedProcess);
然后继续尝试在此处添加一个条件:
A.CallTo(() =>
processSuccessResult
.HandleProcess(A<Action<Process>>.Ignored))
.Invokes((Action<Process> action) => action(fakeExpectedProcess));
为了完成最后一点,变量processSuccessResult
需要是接口的假实例,这样FakeIseasy就可以使用它,并应用您想要的逻辑。
我假设ProcessSuccessResult
是一个你可以访问并且可以编辑的类?如果是这样的话,您应该能够向其中添加一个接口,该接口将包含您需要的方法,这样您以后就可以使用它了。
一旦你定义了它,你应该能够按照如下方式创建你的假对象,其中IProcessSuccessResult
将是你的接口的一个假实现,由FakeItEay:提供
var processSuccessResult = A.Fake<IProcessSuccessResult>();
现在,您应该能够使用A.CallTo(...)
为该伪对象添加逻辑。
当然,这意味着类ProcessSuccessResult
的真正实现是,而不是包含或通过变量processSuccessResult
调用。如果它的一部分需要,那么你可以尝试:
- 添加类似的逻辑,或者使用FakeIseasy的设置代码从伪对象调用它(尽管这可能会变得过于复杂),或者:
- 添加一个单独的变量来包含真实类的一个实例(即分别为两个变量
fakeProcessSuccessResult
和processSuccessResult
),并使用单独的测试来测试这两个类的单独方面及其用法
如果可能的话,我推荐后者。
我希望这一点足够清楚,这将对你有用。我知道有时候要找到测试这种东西的最佳策略可能会很复杂。