23

プロジェクトにコマンドライン インターフェイスを作成しています。ユーザーが「create project foo」と入力すると、「project」を担当するコントローラーが検索Createされ、最初の引数として「foo」を渡してメソッドが呼び出されます。

属性とリフレクションに大きく依存しています。コントローラーは次のようになります。

[ControllerFor("project")]
class ProjectController
{
    [ControllerAction("create")]
    public object Create(string projectName) { /* ... */ }
}

次のように、パーサーの単体テストで Moq を使用したいと思います。

Mock<IProjectsController> controller = new Mock<IProjectsController>();
controller.Expect(f => f.Create("foo"));

parser.Register(controller.Object);
parser.Execute("create project foo");

controller.VerifyAll();

インターフェイスに属性を追加しても機能しないようです。それらは派生クラスに継承されません。

モックされているクラスに Moq に属性を追加させることはできますか?

4

1 に答える 1

32

更新: TypeDescriptor.AddAttributesを使用して、既存の型に実際に属性を追加できることに気付きました。これは、インスタンスまたは aa 型に対して実行できます。

Mock<IRepository> repositoryMock = new Mock<IRepository>();

CustomAttribute attribute = new CustomAttribute();

// option #1: to the instance
TypeDescriptor.AddAttributes(repositoryMock.Object, attribute );

// option #2: to the generated type
TypeDescriptor.AddAttributes(repositoryMock.Object.GetType(), attributes);

必要に応じて、AddAttribute は TypeDescriptorProvider を返します。これを TypeDescriptor.RemoveProvider に渡して、後で属性を削除できます。

Attribute.GetCustomAttributesは、実行時にこの方法で追加された属性を検出しないことに注意してください。代わりに、TypeDescriptor.GetAttributesを使用してください。

元の回答

Moq (またはその他のモック フレームワーク) がカスタム属性をサポートしているとは思えません。Castle Proxy (実際にクラスを作成するために一般的に使用されるフレームワーク)それをサポートしていることは知っていますが、Moq を介してアクセスする方法はありません。

あなたの最善の策は、属性をロードするメソッドをインターフェイス (タイプと属性タイプを受け入れる) に抽象化し、それをモックすることです。

編集:例:

public interface IAttributeStrategy
{
    Attribute[] GetAttributes(Type owner, Type attributeType, bool inherit);
    Attribute[] GetAttributes(Type owner, bool inherit);
}

public class DefaultAttributeStrategy : IAttributeStrategy
{
    public Attribute[] GetAttributes(Type owner, Type attributeType, bool inherit)
    {
        return owner.GetCustomAttributes(attributeType, inherit);
    }

    public Attribute[] GetAttributes(Type owner, bool inherit)
    {
        return owner.GetCustomAttributes(inherit);
    }
}

属性を必要とするクラスは、IAttributeStrategy のインスタンスを使用します (IoC コンテナーを使用するか、オプションでコンストラクターに渡します)。通常は DefaultAttributeStrategy になりますが、出力をオーバーライドするために IAttributeStrategy をモックできるようになりました。

複雑に聞こえるかもしれませんが、実際に属性をモックしようとするよりも、抽象化のレイヤーを追加する方がはるかに簡単です。

于 2009-02-12T09:53:02.267 に答える