我的测试类在其构造函数中使用了2个对象,一个数据加载器和一个使用数据加载器返回的数据的类。
数据加载器接口有两个函数,LoadCompanies()和LoadEmployees(),它们都接受一个int参数并返回一个IEnumerable。
如何验证测试中的方法是否将LoadCompanies()和NOT LoadEmployees()传递到数据使用者类中?
这是我的代码:
[TestFixture]
public class TestingFunctionalParameters_UT
{
[Test]
public void Correct_Loader_Method_is_Used()
{
const int userId = 1;
var companies = new[] { "c1", "c2" };
var dataLoader = MockRepository.GenerateMock<ITestDataLoader>();
var dataConsumer = MockRepository.GenerateMock<IDataConsumerClass>();
var testObject = new TestClass(dataLoader, dataConsumer);
dataConsumer.Expect(fc => fc.LoadIt(Arg<Func<IEnumerable<string>>>.Is.TypeOf)).Return(true);
//TODO: validate that correct dataloader function was called...
//dataLoader.Expect(dl => dl.LoadCompanies(userId)).Return(companies);
var result = testObject.Run(userId);
Assert.That(result, Is.True);
dataLoader.VerifyAllExpectations();
dataConsumer.VerifyAllExpectations();
}
}
public class TestClass
{
private readonly ITestDataLoader dataLoader;
private readonly IDataConsumerClass funcClass;
public TestClass(ITestDataLoader dataLoader, IDataConsumerClass funcClass)
{
this.dataLoader = dataLoader;
this.funcClass = funcClass;
}
public bool Run(int userId)
{
Func<IEnumerable<string>> loadFn = () => dataLoader.LoadCompanies(userId);
return funcClass.LoadIt(loadFn);
}
}
public interface ITestDataLoader
{
IEnumerable<string> LoadCompanies(int userId);
IEnumerable<string> LoadEmployees(int userId);
}
public interface IDataConsumerClass
{
bool LoadIt(Func<IEnumerable<string>> load);
}
答案 0 :(得分:1)
您可以创建公司和员工类
class Company
{
public Company(string name)
{
Name = name;
}
public string Name { get; private set; }
public override string ToString()
{
return Name;
}
}
对员工执行相同操作,然后像这样定义您的界面
public interface ITestDataLoader
{
IEnumerable<Company> LoadCompanies(int userId);
IEnumerable<Employee> LoadEmployees(int userId);
}
现在公司和员工不能再混淆了。
编辑:
如果你有很多这样的案例,你可以创建一个公共基类
class NamedItem
{
public NamedItem(string name)
{
Name = name;
}
public string Name { get; private set; }
public override string ToString()
{
return Name;
}
}
class Company : NamedItem
{
public Company(string name)
: base(name)
{
}
}
class Employee : NamedItem
{
public Employee (string name)
: base(name)
{
}
}
答案 1 :(得分:0)
(编辑:我假设您的示例是简化示例,并且您的实际实现是尝试测试委托注入模式)
也许你可以这样写你的测试? (编辑实际编译)
[Test]
public void Correct_Loader_Method_is_Used()
{
const int userId = 1;
var companies = new[] { "c1", "c2" };
var dataLoader = MockRepository.GenerateMock<ITestDataLoader>();
var dataConsumer = MockRepository.GenerateMock<IDataConsumerClass>();
var testObject = new TestClass(dataLoader, dataConsumer);
dataConsumer.Expect(fc => fc.LoadIt(Arg<Func<IEnumerable<string>>>.Matches(x => x().Any()))).Return(true);
//validate that correct dataloader function was called...
dataLoader.Expect(dl => dl.LoadCompanies(userId)).Return(companies);
// Fails if you uncomment this line
//dataLoader.Expect(dl => dl.LoadEmployees(userId)).Return(companies);
var result = testObject.Run(userId);
Assert.That(result, Is.True);
dataLoader.VerifyAllExpectations();
dataConsumer.VerifyAllExpectations();
}
基本上Matches()约束会尝试执行该方法,如果它试图调用LoadEmployees(),RhinoMocks会抱怨,因为它没有定义的模拟。
更新:处理Action<T>
代表
这可能不太健壮,但对于Action<T>
s:
public interface IDataConsumerClass
{
bool LoadIt(Func<IEnumerable<string>> load);
bool ExecuteIt<T>(Action<T> execute);
}
//...
dataConsumer.Expect(fc => fc.ExecuteIt(Arg<Action<int>>.Matches(x => ActionWrapper(x, userId)))).Return(true);
//...
private bool ActionWrapper<T>(Action<T> action, T arg)
{
action(arg);
return true;
}