我正在为我的项目编写一个命令行界面。用户输入“create project foo”,它会找到负责“project”的 Controller ,然后调用 Create
方法,将“foo”作为第一个参数传递。
它在很大程度上依赖于属性和反射: Controller 看起来像这样:
[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();
将属性添加到接口(interface)似乎不起作用——它们不是由派生类继承的。
我能否让 Moq 为被模拟的类添加属性?
最佳答案
更新:我刚刚意识到您实际上可以使用 TypeDescriptor.AddAttributes 向现有类型添加属性。 ,可以针对实例或类型执行:
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 访问它。
最好的办法是抽象将属性加载到接口(interface)(接受 Type 和 Attribute 类型)的方法,然后模拟它。
编辑:例如:
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 以覆盖输出。
这听起来可能很复杂,但是添加一个抽象层比尝试实际模拟属性要容易得多。
关于c# - 我可以让 Moq 为模拟类添加属性吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/540636/