在当前的一个项目中,我正在与一个坚持认为代码生成对单元测试有害的客户打交道。他们团队中的一些技术/评估人员是非常有经验的开发人员,所以这让我感到惊讶。如此之多,以至于在看到他们的个人资料后,我正在就一个我不会质疑的主题(即自动化)征求社区意见。
标题是指用于创建单元测试的代码生成。根据场景,可以在不同程度上做到这一点。我自己编写了这个特定的库,并认为它在分支、复杂性、可维护性等方面非常简单。下面列出了一个摘要来说明这一点。
有问题的库是一个通用的有限状态机,它使用两个枚举来确定可能的states
和commands
. 命令用于指定抽象事务,而明确的任意状态也可以在没有命令的情况下请求,只要它是合法的。状态示例包括 Processing、Cancelled、WaitingForUserInput 等。命令示例包括 WakeUp、Sleep、StartProcessing 等。
声明如下:
// Both [TState] and [TCommand] will ALWAYS be enumerations.
public abstract class StateMachineBase<TState, TCommand>: IDisposable
{
public delegate void DelegateStart (StateMachineBase<TState, TCommand> sender, EventArgs e);
public delegate void DelegateStop (StateMachineBase<TState, TCommand> sender, EventArgs e);
public delegate void DelegateTransitionRequest (StateMachineBase<TState, TCommand> sender, TransitionRequestEventArgs<TState, TCommand> e);
public delegate void DelegateTransitionComplete (StateMachineBase<TState, TCommand> sender, TransitionCompletedEventArgs<TState, TCommand> e);
public event DelegateStart OnStart = null;
public event DelegateStop OnStop = null;
public event DelegateTransitionRequest OnTransitionRequest = null;
public event DelegateTransitionComplete OnTransitionComplete = null;
private readonly object _SyncRoot = new object(); // Thread safety.
public bool Running { get; private set; }
public TState State { get; private set; }
private TCommand Command { get; set; }
private List<Transition<TState, TCommand>> AllowedTransitions { get; set; }
// Will not work if the machine is running.
protected void AddTransition (TState from, TState to, TCommand command) { ... }
public void Start () { ... }
public void Stop () { ... }
public bool CanTransit (TState state) { ... }
public bool CanTransit (TCommand command) { ... }
public bool Request (TState state) { ... }
public bool Request (TCommand command) { ... }
}
我确实意识到在某些情况下,使用代码生成可能会破坏编写单元测试的目的,但我相信许多开发人员确实在特定场景中使用它。我想,如果我自己编写了库,我应该能够正确地进行单元测试,无论是手动还是反射。
问题是,在这种情况下使用代码生成是否明智?如果没有,我会忽略哪些意外后果?