没有两种方法。如果您为所有代码编写隔离的原子单元测试,则不会经常使用ReSharper的建议和C#的一些有用功能。
例如,如果您有一个静态方法,并且需要将其存根,则除非使用基于概要文件的隔离框架,否则您将无法这样做。兼容呼叫的解决方法是更改方法的顶部以使用lambda表示法。例如:
之前:
public static DBConnection ConnectToDB( string dbName, string connectionInfo ) {
}
后:
public static Func<string, string, DBConnection> ConnectToDB (dbName, connectionInfo ) {
};
两者是呼叫兼容的。呼叫者不必更改。函数的主体保持不变。
然后,在单元测试代码中,您可以像下面这样对这个调用进行存根(假设它在一个名为Database的类中):
Database.ConnectToDB = (dbName, connectionInfo) => { return null|whatever; }
完成后,请小心将其替换为原始值。您可以通过try / finally进行操作,或者在每次单元测试后进行的每次测试后调用的代码中编写如下代码:
[TestCleanup]
public void Cleanup()
{
typeof(Database).TypeInitializer.Invoke(null, null);
}
这将重新调用您的类的静态初始值设定项。
Lambda Funcs不像常规静态方法那样具有丰富的支持,因此该方法具有以下不良副作用:
- 如果静态方法是扩展方法,则必须首先将其更改为非扩展方法。Resharper可以自动为您执行此操作。
- 如果静态方法的任何数据类型都是嵌入式互操作程序集(例如Office),则必须包装该方法,包装该类型或将其更改为“对象”类型。
- 您不能再使用Resharper的更改签名重构工具。
但是,假设您完全避免使用静态方法,并将其转换为实例方法。除非该方法是虚拟的或作为接口的一部分实现的,否则它仍然不可模仿。
因此,实际上,任何建议对静态方法进行存根的补救措施是使它们成为实例方法,它们也将针对非虚拟或接口一部分的实例方法。
那么,为什么C#具有静态方法?为什么它允许使用非虚拟实例方法?
如果使用这两个“功能”中的任何一个,则根本无法创建隔离的方法。
那么什么时候使用它们呢?
将它们用于任何您不希望任何人都想存根的代码。一些示例:String类的Format()方法,Console类的WriteLine()方法,Math类的Cosh()方法
还有一件事..大多数人都不会在意这一点,但是如果您可以在意间接调用的性能,那是避免使用实例方法的另一个原因。在某些情况下,它会影响性能。这就是为什么非虚拟方法首先存在的原因。