通过分解批处理任务来增强可测试性

时间:2013-03-19 13:23:34

标签: c# dependency-injection decomposition

我似乎无法找到关于此的更多信息所以我想我会把它带到这里。我经常遇到的一个问题是在处理列表时单元测试单个对象的创建。例如,我有一个方法签名,例如IEnumerable<Output> Process(IEnumerable<Input> inputs)。当单元测试单个输入时,我会创建一个输入的列表,只需在结果上调用First()并确保它符合我的预期。这会产生如下内容:

public class BatchCreator
{
    public IEnumerable<Output> Create(IEnumerable<Input> inputs)
    {
        foreach (var input in inputs)
        {
            Console.WriteLine("Creating Output...");
            yield return new Output();
        }
    }
}

我目前的想法是,也许一个类应该负责创建对象,而另一个类负责编排我的输入列表。见下面的例子。

public interface ICreator<in TInput, out TReturn>
{
    TReturn Create(TInput input);
}

public class SingleCreator : ICreator<Input, Output>
{
    public Output Create(Input input)
    {
        Console.WriteLine("Creating Output...");
        return new Output();
    }
}

public class CompositeCreator : ICreator<IEnumerable<Input>, IEnumerable<Output>>
{
    private readonly ICreator<Input, Output> _singleCreator;

    public CompositeCreator(ICreator<Input, Output> singleCreator)
    {
        _singleCreator = singleCreator;
    }

    public IEnumerable<Output> Create(IEnumerable<Input> inputs)
    {
        return inputs.Select(input => _singleCreator.Create(input));
    }
}

通过上面发布的内容,我可以轻松地测试我能够创建一个Output的单个实例给定Input。请注意,除SingleCreator之外,我无需在代码库中的任何其他位置调用CompositeCreator。创建ICreator也可以让我在其他时间重复使用它,我需要做类似的任务,我目前在当前的项目中做了2-3次

任何人都有这方面的经验可以解释一下吗?我只是过度思考这个吗?建议非常感谢。

2 个答案:

答案 0 :(得分:2)

一般来说,你的推理没有任何内在错误。或多或少是问题如何解决。

但是,您的CompositeCreator实际上并不是复合的,因为它只使用了一种“创建方法”。

很难说更多,因为我们不知道你的项目内部,但如果它很好地集成到你的用例中,那就没关系了。我要尝试的是仅使用ICreator<Tin, Tout>并使用扩展方法IEnumerable<Tout> CreateMany(this IEnumerable<Tin> c)来处理集合。您可以轻松地独立测试(假ICreator并检查是否处理了输入集合)。这样你就可以摆脱ICreator<IEnumerable, ...>,这通常很好,因为作为一个整体进行集合操作并对单个项目进行操作通常不能很好地协同工作。

答案 1 :(得分:1)

我不完全确定为什么你需要IEnumerable输入/输出选项,复合创建者,除非它不仅仅是一个集合,因为这是LINQ解决的问题,它看起来像:

var singleCreator = new SingleCreator();
var outputs = InputEnumerable.Select(singleCreator.Create);

我认为这是主观的,并且取决于你传递的类的复杂性 - 如果它不仅仅是一个IEnumerable,那么它是值得拥有某种多重创建者,它可能需要也可能不需要是一个类。< / p>