1

私はクラスのこの最初のバージョンを持っています

public class GenerateAuthorisationWorkflows : IGenerateAuthorisationWorkflows
{
    public IList<Guid> FromDtaObjects(IList<DtaObject> dtaObjects, Employee requestingEmployee)
    {
        foreach (var dtaObject in dtaObjects) { }
        return new List<Guid>();
    }

    public IList<Guid> FromDtaObjects()
    {
        return new List<Guid>();
    }
}

そしてMSpecはそれをテストします

public abstract class specification_for_generate_workflows : Specification<GenerateAuthorisationWorkflows>
{
    protected static IWorkflowService workflowService;

    Establish context = () => { workflowService = DependencyOf<IWorkflowService>(); };
}

[Subject(typeof(GenerateAuthorisationWorkflows))]
public class when_generate_workflows_is_called_with_a_dta_object_list_and_an_employee : specification_for_generate_workflows
{
    static IList<Guid> result;
    static IList<DtaObject> dtaObjects;
    static Employee requestingEmployee;

    Establish context = () =>
    {
         var mocks = new MockRepository();
         var stubDtaObject1 = mocks.Stub<DtaObject>();
         var stubDtaObject2 = mocks.Stub<DtaObject>();
         var dtaObjectEnum = new List<DtaObject>{stubDtaObject1,stubDtaObject2}.GetEnumerator();
         dtaObjects = mocks.Stub<IList<DtaObject>>();
         dtaObjects.Stub(x => x.GetEnumerator()).Return(dtaObjectEnum).WhenCalled(x => x.ReturnValue = dtaObjectEnum);
         requestingEmployee = mocks.Stub<Employee>();
         mocks.ReplayAll();
    };

    Because of = () => result = subject.FromDtaObjects(dtaObjects, requestingEmployee);

    It should_enumerate_the_dta_objects = () => dtaObjects.received(x=> x.GetEnumerator());
    It should_call_workflow_host_helper = () => workflowService.AssertWasCalled(x => x.StartWorkflow());
}

この構成では、予想どおり、最初のテストはパスし、2 番目のテストは失敗します。クラスにコンストラクターを追加して、IWorkflowService.

public class GenerateAuthorisationWorkflows : IGenerateAuthorisationWorkflows
{
    IWorkflowService _workflowService;

    GenerateAuthorisationWorkflows(IWorkflowService workflowService)
    {
        _workflowService = workflowService;
    }

    public IList<Guid> FromDtaObjects(IList<DtaObject> dtaObjects, Employee requestingEmployee)
    {
        foreach (var dtaObject in dtaObjects)
        {
            Guid workflowKey = _workflowService.StartWorkflow();
        }

        return new List<Guid>();
    }

    public IList<Guid> FromDtaObjects()
    {
        return new List<Guid>();
    }
}

ここで、テストを実行すると、次の場所で失敗しますBecause:

System.InvalidOperationException: Sequence contains no elements
at System.Linq.Enumerable.First(IEnumerable`1 source)
at MSpecTests.EmployeeRequestSystem.Tasks.Workflows.when_generate_workflows_is_called_with_a_dta_object_list_and_an_employee.<.ctor>b__4() in GenerateAuthorisationWorkflowsSpecs.cs: line 76 

わかりやすくするために、上記の 76 行目は次のとおりです。

Because of = () => result = subject.FromDtaObjects(dtaObjects, requestingEmployee);

問題を追跡しようとしましたが、運がありません。引数を取らないコンストラクターを設定しようとしましたが、同じエラーが発生します。MSpec/Rhino モックを使用して正常に動作する IoC 依存関係を持つ同様のクラスがありますが、どこが間違っていますか?

4

2 に答える 2

1

Castle Windsor では、クラスをインスタンス化するために public コンストラクターが必要です。コンストラクターに追加publicすると、正しい操作が可能になります。

public class GenerateAuthorisationWorkflows : IGenerateAuthorisationWorkflows
{
    IWorkflowService _workflowService;

    public GenerateAuthorisationWorkflows(IWorkflowService workflowService)
    {
        _workflowService = workflowService;
    }

    public IList<Guid> FromDtaObjects(IList<DtaObject> dtaObjects, Employee requestingEmployee)
    {
        foreach (var dtaObject in dtaObjects)
        {
            Guid workflowKey = _workflowService.StartWorkflow();
        }

        return new List<Guid>();
    }

    public IList<Guid> FromDtaObjects()
    {
        return new List<Guid>();
    }
}
于 2012-09-13T17:12:10.967 に答える
0

ローワン、あなたは自分の質問に答えたようです。アクセス修飾子を明示的に記述することをお勧めします。デフォルトでは、C# は を選択しprivateます。この種のエラーは見逃されがちです。

Establishまた、ブロックが複雑すぎることもわかります。動作ではなく、実装の詳細をテストしています。たとえば、あなたは

  • ループGetEnumerator内で暗黙的に行われた呼び出しをスタブします。foreach
  • ワークフロー サービスが1 回だけ呼び出されたと主張する
  • MSpec 自動モックと独自のローカル モックの混合

入力リスト内のすべてのオブジェクトの GUID を取得したことを実際にテストしているわけではありません。 私があなたなら、このような動作をテストします...

public class GenerateAuthorisationWorkflows : IGenerateAuthorisationWorkflows
{
    private readonly IWorkflowService _service;

    public GenerateAuthorisationWorkflows(IWorkflowService service)
    {
        _service = service;
    }

    public List<Guid> FromDtaObjects(List<DtaObject> input, Employee requestor)
    {
        // I assume that the workflow service generates a new key
        // per input object. So, let's pretend the call looks like
        // this. Also using some LINQ to avoid the foreach or 
        // building up a local list.
        input.Select(x => _service.StartWorkflow(requestor, x)).ToList();
    }
}

[Subject(typeof(GenerateAuthorisationWorkflows))]
public class When_generating_authorisation_keys_for_this_input 
    : Specification<GenerateAuthorisationWorkflows>
{
    private static IWorkflowService _service;
    private static Employee _requestor = new Employee();
    private static List<DtaObject> _input = new List<DtaObject>() 
    {
        new DtaObject(),
        new DtaObject(),
    };
    private static List<Guid> _expected = new List<Guid>()
    {
        Guid.NewGuid(),
        Guid.NewGuid(),
    };

    private static List<Guid> _actual = new List<Guid>();

    Establish context = () =>
    {
        // LINQ that takes each item from each list in a pair. So
        // the service is stubbed to return a specific GUID per 
        // input DtaObject.
        _input.Zip(_expected, (input, output) => 
        {
            DependencyOf<IWorkflowService>().Stub(x => x.StartWorkflow(_requestor, input)).Return(output);
        });
    };

    Because of = () => _actual = Subject.FromDtaObjects(_input, _requestor);

    // This should be an MSpec collection assertion that 
    // ensures that the contents of the collections are
    // equivalent
    It should_get_a_unique_key_per_input = _actual.ShouldEqual(_expected);
}
于 2012-12-03T21:55:29.150 に答える