MSI*_*MSI 8 .net tdd domain-driven-design
我是TDD和DDD的新手,我有一个关于静态方法的简单问题.TDD的大多数专家用一句话说静态方法是坏的(我们应该忘记创建大量的静态实用程序,我们(或我)以前用过它们是不可测试的.我可以看出为什么它们是不可测试(这里可以找到一个很棒的澄清文章,对于那些感兴趣的人,但我想我是这里唯一的菜鸟:()但是我想知道从TDD角度来看使用静态有一个很好的干净指南吗?
对于大多数人来说,这可能是一个非常愚蠢的问题,但是一些提示会很棒,我只想知道这里的专家如何看待静态的东西.提前致谢.
编辑:在寻找答案的过程中,我找到了2个关于静态使用的其他好线程(虽然不是TDD关注),我觉得对于那些感兴趣的人(我自己也包括在内)很好.
adr*_*nks 11
我想你可能会有些误解.
静态方法是可测试的.以此方法为例:
public static int Add(int x, int y)
{
return x + y;
}
Run Code Online (Sandbox Code Playgroud)
您可以通过根据传入的参数测试返回值是否符合预期来测试此值.
当测试是需要引入模拟时,静态方法变得麻烦.
假设我有一些调用File.Delete()静态方法的代码.为了在不依赖文件系统的情况下测试我的代码,我想用一个测试版本替换/模拟这个调用,该测试版本只是验证它是从被测试的代码调用的.如果我有一个Delete()正在调用的对象的实例,这很容易做到.大多数(所有?)模拟框架都不能模拟静态方法,因此在我的代码中使用静态方法迫使我以不同方式测试它(通常通过调用真正的静态方法).
为了测试这样的东西,我会介绍一个接口:
interface IFileDeleter
{
void Delete(string file);
}
Run Code Online (Sandbox Code Playgroud)
然后我的代码将获取一个实现此接口的对象的实例(在方法调用中或作为构造函数中的参数),然后调用其Delete()方法执行删除:
void MyMethod(string file)
{
// do whatever...
deleter.Delete(file);
}
Run Code Online (Sandbox Code Playgroud)
为了测试这个,我可以模拟IFileDeleter界面并简单地验证它的Delete()方法已被调用.这消除了将实际文件系统作为测试的一部分的需要.
这可能看起来像代码更复杂(它是),但它使自己付出代价更容易测试.
避免静态当然是要走的路,但是当你不能或者你正在使用Legacy代码时,可以使用以下选项.继上面的adrianbanks回答之后,假设您有以下代码(道歉,它在Java中,因为我不知道C#):
public void someMethod() {
//do somethings
File.delete();
//do some more things
}
Run Code Online (Sandbox Code Playgroud)
您可以将File.delete()重构为自己的方法,如下所示:
public void someMethod() {
//do somethings
deleteFile();
//do some more things
}
//protected allows you to override in a subclass
protected void deleteFile() {
File.delete();
}
Run Code Online (Sandbox Code Playgroud)
然后在准备你的单元测试时创建一个mock类,它扩展了原来的一个并且存根该功能:
//Keep all the original functionality, but stub out the file delete functionality to
//prevent it from using the real thing and while you're at it, keep a record that the
//method was called.
public class MockClass extends TheRealClass {
boolean fileDeleteCalled = false;
@Override
protected void deleteFile()
//don't actually delete the file,
//just record that the method to do so was called
fileDeleteCalled = true;
}
public boolean fileDeleteCalled() {
return fileDeleteCalled;
}
}
Run Code Online (Sandbox Code Playgroud)
最后在你的单元测试中:
//This would normally be instantiated in the @Before method
private MockClass unitUnderTest = new MockClass();
@Test
public void testFileGetsDeleted(){
assertFalse(unitUnderTest.fileDeleteCalled());
unitUnderTest.someMethod();
assertTrue(unitUnderTest.fileDeleteCalled());
}
Run Code Online (Sandbox Code Playgroud)
现在你已经执行了someMethod()的所有功能而没有实际删除文件,你仍然能够看到是否调用了该方法.
一般来说,如果方法:
然后避免让它静止.(请参阅@adrianbanks的答案,以便对此背后的原因和替代方案进行精彩讨论.)
基本上,如果它是一个简短的内存中方便方法(如许多扩展方法),只能使它静态.
| 归档时间: |
|
| 查看次数: |
1229 次 |
| 最近记录: |