我可以让 Moq 为模拟类添加属性吗? [英] Can I get Moq to add attributes to the mock class?

查看:37
本文介绍了我可以让 Moq 为模拟类添加属性吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在为我的项目编写一个命令行界面.用户输入create project foo",找到负责project"的控制器,然后调用Create方法,传入foo"作为第一个参数.

它在很大程度上依赖于属性和反射:控制器看起来像这样:

[ControllerFor("project")]类项目控制器{[控制器动作(创建")]公共对象创建(字符串项目名称){/* ... */}}

我想在解析器的单元测试中使用 Moq,如下所示:

Mock控制器=新的模拟<IProjectsController>();controller.Expect(f => f.Create("foo"));parser.Register(controller.Object);parser.Execute("创建项目 foo");控制器.VerifyAll();

向接口添加属性似乎不起作用——它们没有被派生类继承.

我可以让 Moq 为被模拟的类添加属性吗?

解决方案

更新: 我刚刚意识到你可以通过使用 TypeDescriptor.AddAttributes,可以针对实例或aa类型执行:

Mock<IRepository>repositoryMock = new Mock<IRepository>();CustomAttribute 属性 = new CustomAttribute();//选项 #1:实例TypeDescriptor.AddAttributes(repositoryMock.Object, 属性);//选项#2:生成的类型TypeDescriptor.AddAttributes(repositoryMock.Object.GetType(), 属性);

如果需要,AddAttribute 会返回一个 TypeDescriptorProvider,它可以传递给 TypeDescriptor.RemoveProvider 之后删除属性.

请注意 属性.GetCustomAttributes 不会找到以这种方式在运行时添加的属性.相反,请使用 TypeDescriptor.GetAttributes.p>

原答案

我不相信 Moq(或任何其他模拟框架)支持自定义属性.我知道 Castle Proxy(通常用于实际创建类的框架)确实支持它,但无法通过 Moq 访问它.

最好的办法是将加载属性的方法抽象到接口(接受类型和属性类型)中,然后模拟它.

例如:

公共接口IAttributeStrategy{Attribute[] GetAttributes(Type owner, Type attributeType, bool inherit);Attribute[] GetAttributes(Type owner, bool inherit);}公共类 DefaultAttributeStrategy : IAttributeStrategy{public Attribute[] GetAttributes(Type owner, Type attributeType, bool inherit){return owner.GetCustomAttributes(attributeType, inherit);}public Attribute[] GetAttributes(类型所有者,bool 继承){return owner.GetCustomAttributes(inherit);}}

需要属性的类使用 IAttributeStrategy 的实例(通过 IoC 容器,或者将其可选地传递给构造函数).通常它将是一个 DefaultAttributeStrategy,但您现在可以模拟 IAttributeStrategy 以覆盖输出.

这听起来可能令人费解,但添加抽象层比尝试实际模拟属性要容易得多.

I'm writing a command-line interface to my project. The user enters "create project foo", and it finds the controller responsible for "project" and then invokes the Create method, passing "foo" as the first argument.

It relies heavily on attributes and reflection: the controller looks something like this:

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

I'd like to use Moq in the unit tests for the parser, something like this:

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

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

controller.VerifyAll();

Adding the attributes to the interface doesn't appear to work -- they're not inherited by derived classes.

Can I get Moq to add attributes to the class being mocked?

解决方案

Update: I've just realised that you can actually add attributes to an existing type by using TypeDescriptor.AddAttributes, which can be executed against an instance or a a type:

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);

If you need it, AddAttribute returns a TypeDescriptorProvider that can be passed to TypeDescriptor.RemoveProvider to remove the attributes afterwards.

Be aware that Attribute.GetCustomAttributes will not find attributes added at runtime in this way. Instead, use TypeDescriptor.GetAttributes.

Original Answer

I don't belive Moq (or any other mocking framework for that matter) supports custom attributes. I do know that Castle Proxy (the framework commonly used to actually create the class) does support it, but there'd be no way to access it through Moq.

Your best bet is to abstract your method of loading Attributes into an interface (that accepts the Type and the Attribute type) and then mock that.

Edit: For example:

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

The class that needs the attributes uses an instance of IAttributeStrategy (either through an IoC container, or having it optionally passed into the constructor). Usually it will be a DefaultAttributeStrategy, but you can now mock IAttributeStrategy in order to override the output.

It might sound convoluted, but adding a layer of abstraction is much easier than attempting to trying to actually mock Attributes.

这篇关于我可以让 Moq 为模拟类添加属性吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆