给定一组可以同时调用Execute()方法的命令,有没有办法对命令类进行单元测试,以确保代码的其他维护者不会添加成员数据(除了只传入成员数据的readonly成员)构造函数)?
实施例: 代码启动时,在脚本操作和可以为操作提供服务的命令之间创建映射:
actionCommandTable =
[“Translate”, new TranslateCommand(appcontext)],
[“Scale”, new ScaleCommand(appcontext)],
[“Assignment” new AssignmentCommand(appcontext, expressionEvaluator)]
然后在运行时:
actionCommandTable[“Translate”].Execute(actionDataContext);
翻译命令:
public class TranslateAction : ActionCommand {
//read-only interface
private readonly AliasProvider aliasMap;
//bad - need to prevent this instance from being added - will be overwritten unexpectedly
private int transientValue;
public TranslateAction(IAppContext appContext) {
aliasMap = appContext.AliasMap;
}
public override async Task Execute(ActionDataContext actionDataContext) {
//assign to transientValue
//do some work
//await an animation
//do more work
//read from transientValue
}
}
在此示例中,如果Execute中的所有工作对共享成员不起作用,则该工作正常。
actionDataContext旨在成为瞬态有状态数据的目标。
答案 0 :(得分:2)
您可以使用反射来确保所有字段和属性都是只读的。但是,为了验证分配是否正确,您可能必须根据您的要求验证命令值分配
public void ValidateAllFieldsAreInitOnly(Type sut)
{
foreach(var field in sut.GetFields(BindingFlags.NonPublic |
BindingFlags.Instance |
BindingFlags.Static |
BindingFlags.Public))
{
Assert.IsTrue(field.IsInitOnly);
}
foreach (var property in sut.GetProperties(BindingFlags.NonPublic |
BindingFlags.Instance |
BindingFlags.Static |
BindingFlags.Public))
{
// returns true if the property has a set accessor, even if the accessor is private, internal
Assert.IsFalse(property.CanWrite);
// OR can use depending on requirement
// The MethodInfo object representing the Set method for this property if the set accessor is public, or null if the set accessor is not public.
Assert.IsNull(property.GetSetMethod());
}
}
请注意,当有人将属性声明为只读时,这将不会捕获情况,但是会以错误的方式初始化它 -
的测试绿色
public class GoodCommand
{
private readonly string privateField1;
private readonly string privateField2;
public GoodCommand(string field1, string field2)
{
privateField1 = field1;
privateField2 = field2;
}
}
测试将捕获(红色)
public class BadCommand
{
private readonly string privateField1;
private string privateField2;
public BadCommand(string field1)
{
privateField1 = field1;
privateField2 = "testingbadCommand";
}
}
对于此案例,测试为绿色,因为正确的分配检查可能会根据要求而有所不同。您也可以通过验证分配的值是否符合预期来捕获此方案。
public class SmartBadCommand
{
private readonly string privateField1;
private readonly string privateField2;
public SmartBadCommand(string field1)
{
privateField1 = field1;
privateField2 = "testingbadCommand";
}
}
希望得到这个帮助。