最小起订量和属性
Moq and attributes
我正在尝试创建一个测试用例,我需要在模拟对象上设置一个属性。我一直在关注 this question 中的答案,但 CommandEventProcessingDecorator
方法中的属性为 null。
[Fact]
public void RaiseEvent_AfterCommandIsExecuted_WhenCommandIsAttributedWithRaiseEventEnabled()
{
var command = new FakeCommand();
Assert.IsAssignableFrom<ICommand>(command);
var eventProcessor = new Mock<IProcessEvents>(MockBehavior.Strict);
eventProcessor.Setup(x => x.Raise(command));
var attribute = new RaiseEventAttribute
{
Enabled = true
};
var decorated = new Mock<IHandleCommand<FakeCommand>>(MockBehavior.Strict);
TypeDescriptor.AddAttributes(decorated.Object, attribute); // Add the attribute
decorated.Setup(x => x.Handle(command));
var decorator = new CommandEventProcessingDecorator<FakeCommand>(eventProcessor.Object, () => decorated.Object);
decorator.Handle(command);
decorated.Verify(x => x.Handle(command), Times.Once);
eventProcessor.Verify(x => x.Raise(command), Times.Once);
}
internal sealed class CommandEventProcessingDecorator<TCommand> : IHandleCommand<TCommand> where TCommand : ICommand
{
private readonly IProcessEvents _events;
private readonly Func<IHandleCommand<TCommand>> _handlerFactory;
public CommandEventProcessingDecorator(IProcessEvents events, Func<IHandleCommand<TCommand>> handlerFactory)
{
_events = events;
_handlerFactory = handlerFactory;
}
public void Handle(TCommand command)
{
var handler = _handlerFactory();
handler.Handle(command);
var attribute = handler.GetType().GetCustomAttribute<RaiseEventAttribute>(); // attribute
if (attribute != null && attribute.Enabled)
{
_events.Raise(command);
}
}
}
我做错了什么?
这实际上在 question referenced 中得到了回答。
正如老狐狸在对问题的评论中指出的那样:
请注意,Attribute.GetCustomAttributes
不会找到以这种方式在运行时添加的属性。相反,使用 TypeDescriptor.GetAttributes.
我创建了一个获取属性的扩展方法:
/// <summary>
/// Gets a runtime added attribute to a type.
/// </summary>
/// <typeparam name="TAttribute">The attribute</typeparam>
/// <param name="type">The type.</param>
/// <returns>The first attribute or null if none is found.</returns>
public static TAttribute GetRuntimeAddedAttribute<TAttribute>(this Type type) where TAttribute : Attribute
{
if (type == null) throw new ArgumentNullException(nameof(type));
var attributes = TypeDescriptor.GetAttributes(type).OfType<TAttribute>();
var enumerable = attributes as TAttribute[] ?? attributes.ToArray();
return enumerable.Any() ? enumerable.First() : null;
}
用法:myClass.getType().GetRuntimeAddedAttribute<CustomAttribute>();
我正在尝试创建一个测试用例,我需要在模拟对象上设置一个属性。我一直在关注 this question 中的答案,但 CommandEventProcessingDecorator
方法中的属性为 null。
[Fact]
public void RaiseEvent_AfterCommandIsExecuted_WhenCommandIsAttributedWithRaiseEventEnabled()
{
var command = new FakeCommand();
Assert.IsAssignableFrom<ICommand>(command);
var eventProcessor = new Mock<IProcessEvents>(MockBehavior.Strict);
eventProcessor.Setup(x => x.Raise(command));
var attribute = new RaiseEventAttribute
{
Enabled = true
};
var decorated = new Mock<IHandleCommand<FakeCommand>>(MockBehavior.Strict);
TypeDescriptor.AddAttributes(decorated.Object, attribute); // Add the attribute
decorated.Setup(x => x.Handle(command));
var decorator = new CommandEventProcessingDecorator<FakeCommand>(eventProcessor.Object, () => decorated.Object);
decorator.Handle(command);
decorated.Verify(x => x.Handle(command), Times.Once);
eventProcessor.Verify(x => x.Raise(command), Times.Once);
}
internal sealed class CommandEventProcessingDecorator<TCommand> : IHandleCommand<TCommand> where TCommand : ICommand
{
private readonly IProcessEvents _events;
private readonly Func<IHandleCommand<TCommand>> _handlerFactory;
public CommandEventProcessingDecorator(IProcessEvents events, Func<IHandleCommand<TCommand>> handlerFactory)
{
_events = events;
_handlerFactory = handlerFactory;
}
public void Handle(TCommand command)
{
var handler = _handlerFactory();
handler.Handle(command);
var attribute = handler.GetType().GetCustomAttribute<RaiseEventAttribute>(); // attribute
if (attribute != null && attribute.Enabled)
{
_events.Raise(command);
}
}
}
我做错了什么?
这实际上在 question referenced 中得到了回答。
正如老狐狸在对问题的评论中指出的那样:
请注意,Attribute.GetCustomAttributes
不会找到以这种方式在运行时添加的属性。相反,使用 TypeDescriptor.GetAttributes.
我创建了一个获取属性的扩展方法:
/// <summary>
/// Gets a runtime added attribute to a type.
/// </summary>
/// <typeparam name="TAttribute">The attribute</typeparam>
/// <param name="type">The type.</param>
/// <returns>The first attribute or null if none is found.</returns>
public static TAttribute GetRuntimeAddedAttribute<TAttribute>(this Type type) where TAttribute : Attribute
{
if (type == null) throw new ArgumentNullException(nameof(type));
var attributes = TypeDescriptor.GetAttributes(type).OfType<TAttribute>();
var enumerable = attributes as TAttribute[] ?? attributes.ToArray();
return enumerable.Any() ? enumerable.First() : null;
}
用法:myClass.getType().GetRuntimeAddedAttribute<CustomAttribute>();