【问题标题】:Resolving multiple Moq objects based on a condition using Autofac使用 Autofac 根据条件解析多个 Moq 对象
【发布时间】:2012-12-28 14:10:13
【问题描述】:

您好,我在创建单元测试时将 Moq 与 Autofac 结合使用。我有一个场景,我的 SUT 多个类型的实例取决于构造函数参数。我想起订这些实例。 我有一个界面ISpanRecord

interface ISpanRecord 
{
RecordType RecordType { get; }
string RecordId { get; set; }
string RecordText { get; set; }
ISpanRecord ParentRecord { get; set; }
List<ISpanRecord> Children { get; }
}

我有另一个接口 IRecordTypeFactory,它在 RecordType(它是一个枚举)的基础上提供了一个新的 ISpanRecord

interface IRecordTypeFactory
{
ISpanRecord GetNewSpanRecord(RecordType recordType);
}

上面的接口被SUT SpanParser类使用

internal class SpanParser : ISpanParser
{
// Private Vars
    private ISpanRecord _spanFile;
    private readonly IRecordTypeFactory _factory;
    private readonly ISpanFileReader _fileReader;

//Constructor
public SpanParser(ISpanFileReader fileReader)
    {
        _fileReader = fileReader;
        _spanFile = Container.Resolve<ISpanRecord>(TypedParameter.From(RecordType.CmeSpanFile),
                                                                TypedParameter.From((List<SpanRecordAttribute>)null));
        _factory = Container.Resolve<IRecordTypeFactory>(TypedParameter.From(_fileReader.PublisherConfiguration));
    }

// Method under test
public SpanRiskDataSetEntity ParseFile()
    {
        string currRecord = string.Empty;
        try
        {
            var treeLookUp = Container.Resolve<ITreeLookUp>(TypedParameter.From(_spanFile),
                                                            TypedParameter.From(_fileReader.PublisherConfiguration));

            IList<string> filterLines = _fileReader.SpanFileLines;

            ISpanRecord currentRecord;
            ISpanRecord previousRecord = _spanFile;
            List<string> spanRecords;

            foreach (var newRecord in filterLines)
            {
                currRecord = newRecord;

                //check if we got multiple type of records in a single line.

                spanRecords = _fileReader.PublisherConfiguration.GetMultipleRecordsText(newRecord);
                if (spanRecords == null)
                    continue;

                foreach (var recordText in spanRecords)
                {
                    RecordType recordType = _fileReader.PublisherConfiguration.GetRecordType(recordText);

                    currentRecord = _factory.GetNewSpanRecord(recordType);

                    // some more logic

                    GetPreviousRecord(ref previousRecord, currentRecord);
                }
            }
            // private method
            return GetSpanRiskDataSet();
        }

        catch (OperationCanceledException operationCanceledException)
        {
            // log
            throw;
        } 
    }

在上面的类中,在测试的时候,我想在RecordType的基础上得到ISpanRecord的多个对象。 比如:

mockFactory.Setup(fc=> fc.GetNewSpanRecord(It.IsAny<RecordType>).Returns(// an ISpanRecord object on the basis of Recordtype)

由于上述设置将在循环中进行验证,所以我想设置多个案例。请让我知道可以解决什么问题,或者指出可以解决的问题。

问候

【问题讨论】:

    标签: unit-testing c#-3.0 moq autofac


    【解决方案1】:

    Returns 有多个重载,您正在寻找那些以Func&lt;RecordType, ISpanRecord&gt; 作为参数的重载。排序后,您可以构建自定义返回逻辑:

    mockFactory
        .Setup(fc => fc.GetNewSpanRecord(It.IsAny<RecordType>)
        .Returns((RecordType rt) =>
        {
             if (rt.Property == "value") return new DummySpanRecord();
             else if (rt.Property2 == "other value") return new FakeSpanRecord();
             else return new DefaultSpanRecord();
        }); 
    

    您使用service locator instead of abstract factory 有什么原因吗?如果您的容器没有嵌入到您的 SUT 中,那么测试可能会更容易(例如,您不必跟踪容器本身和依赖项注册过程)。

    【讨论】:

    • 相反,Service Locator 让它变得更加容易,因为我有时只是添加依赖项的实例(模拟实例)并更新覆盖容器中默认类的容器。我可以在不使用服务定位器的情况下达到同样的效果吗?任何链接或如何做的都将非常感激。
    • @Darsin:通常,您根本不会在单元测试中使用容器。容器应该在应用程序runtime 期间为您连接依赖项,但在测试中您明确地这样做,以便whatever's-going-on 保持透明。服务定位器的问题在于它hides important stuff - 你会记得SpanParser 需要的依赖项比构造函数签名看起来多 3 个,比如从现在开始的 2 个月?
    • 有趣的文章。我之前一直在接收端Autofac。我想我将不得不重新审视它的用法。感谢您的信息
    【解决方案2】:

    在您的设置中,不要使用 It.IsAny&lt;RecordType&gt; - 使用特定值:

    mockFactory.Setup(fc=> fc.GetNewSpanRecord(RecordType.Type1)).Returns(// an ISpanRecord object on the basis of Recordtype.Type1)
    mockFactory.Setup(fc=> fc.GetNewSpanRecord(RecordType.Type2)).Returns(// an ISpanRecord object on the basis of Recordtype.Type2)
    

    编辑:假设RecordType 是枚举(或其他值类型)的简单情况。如果是引用类型,则需要使用更复杂的技术,例如 jimmy's。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-06-12
      • 1970-01-01
      • 1970-01-01
      • 2012-12-14
      • 1970-01-01
      • 1970-01-01
      • 2019-04-12
      • 1970-01-01
      相关资源
      最近更新 更多