验证在函数调用中传递的方法是否正确

本文关键字:方法 是否 函数调用 验证 | 更新日期: 2023-09-27 18:25:22

我的测试类在其构造函数中有两个对象,一个是数据加载器,另一个是使用从数据加载器返回的数据的类。

数据加载器接口有两个函数,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);
}

验证在函数调用中传递的方法是否正确

您可以创建公司和员工类

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)
    {
    }
}

编辑:我假设您的示例是一个简化的示例,而您的实际实现是尝试测试委托注入模式)

也许你可以这样写你的测试?(编辑为实际编译

[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将抱怨,因为它没有定义mock。

更新:处理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;
}