2010-10-19 5 views
8

Я новичок в TDD и DDD, и у меня есть простой вопрос относительно статических методов в целом. Большинство гуру TDD говорят одним словом, что статические методы являются плохими (и что мы должны забыть о создании множества статических утилит, которые мы (um или I) использовали раньше, поскольку они не проверяются. Я понимаю, почему они не тестируемая (замечательная статья уточнения может быть найдена here для тех, кто интересуется, но я думаю, что я единственная нуб здесь :(), но мне было интересно, есть ли хорошее и чистое руководство для использования статики с точки зрения TDD?Статические методы: когда и когда нет

Это может быть действительно глупый вопрос для большинства из вас, но некоторые советы будут замечательными, и я просто хочу знать, как эксперты здесь думают о статических материалах. Спасибо заранее.

Редактировать: При поиске ответа Я нашел 2 других Хорошие темы относительно использования статического (но не TDD), который я думаю, хорошие чтения для тех, кто заинтересован (сам включительно).

ответ

11

Я думаю, что вы, возможно, немного неправильно.

Статические методы можно проверить. Возьмите этот метод в качестве примера:

public static int Add(int x, int y) 
{ 
    return x + y; 
} 

Вы можете проверить это, проверяя, что возвращаемое значение является то, что вы ожидаете на основе аргументов, передаваемых в

Где статические методы становятся хлопотно при тестировании, когда вам нужно. ввести макет.

Предположим, у меня есть код, который вызывает статический метод File.Delete(). Чтобы протестировать мой код, не полагаясь на файловую систему, я хотел бы заменить/высмеять этот вызов тестовой версией, которая просто проверяет, что она была вызвана из проверяемого кода. Это легко сделать, если у меня есть экземпляр объекта, на который вызывается Delete(). Большинство (все?) Mocking frameworks не могут издеваться над статическими методами, поэтому использование статического метода в моем коде заставляет меня тестировать его по-другому (обычно, вызывая реальный статический метод).

Чтобы проверить что-то вроде этого, я хотел бы представить интерфейс:

interface IFileDeleter 
{ 
    void Delete(string file); 
} 

Мой код будет принимать экземпляр объекта, который реализует этот интерфейс (либо в вызове метода или в качестве параметра в конструкторе), а затем вызвать метод Delete() сделать удаления:

void MyMethod(string file) 
{ 
    // do whatever... 
    deleter.Delete(file); 
} 

чтобы проверить это, я могу сделать макет интерфейса IFileDeleter и просто проверить, что его метод Delete() был вызван. Это устраняет необходимость наличия реальной файловой системы как части теста.

Это может выглядеть так, как если бы код был более сложным (каким он есть), но он платит за себя, делая его намного легче проверить.

+0

+1! Typemock может издеваться над статическими методами, но лучше избегать их (когда их нужно будет насмехаться). – TrueWill

+0

+1 Спасибо за кучи за всеобъемлющий ответ. Я просто подожду еще несколько ответов (если они есть), прежде чем выбирать ответ ради обмена знаниями. – MSI

+0

Хм, что я попросил, было действительно немного глупо сейчас, когда я прочитал ваш ответ. да, вы правы, я как бы промахнулся, когда задал вопрос. Это насмехается, когда возникают настоящие проблемы; не тестируя сам метод специально, когда это просто метод утилиты. – MSI

7

В общем, если метод:

  • медленный
  • Длинна
  • Содержит сложную логику
  • использует файловую систему
  • подключается к базе данных
  • Вызывает сеть услуги

, а затем не ставьте его. (См. Ответ @adrianbanks для отличного обсуждения причин этого и альтернатив.)

В принципе, сделайте его статическим, если это короткий метод удобства в памяти (как и многие методы расширения).

+0

Мне очень нравится ваш ответ. Это имеет смысл, вы принимаете удар по тестированию логики статики как части SUT, для удобства, которое статическая утилита приносит вам, если и только в том случае, если у нее нет каких-либо черт, которые вы указали. Поэтому, учитывая быстрый, простой, побочный эффект, статический метод, вы предполагаете, что это примитив, расширение вашего языка и просто используйте его в своих подразделениях без изоляции. –

8

Избегайте статики, конечно, путь, но если вы не можете или работаете с кодом устаревшего кода, доступен следующий вариант. Исходя из adrianbanks ответа выше, скажем, у вас есть следующий код (извинения, его в Java, как я не знаю, C#):

public void someMethod() { 
    //do somethings 
    File.delete(); 
    //do some more things 
} 

вы можете реорганизовать 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(); 
} 

, а затем в рамках подготовки к вашему модульному тестированию создать макет класса, который расширяет оригинал и окурки из этой функциональности:

//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; 
    } 
} 

и, наконец, в тестовом модуле:

//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()); 
} 

Теперь вы выполнили все функциональные SomeMethod() фактически не удаляя файл, и вы все еще есть возможность увидеть, если этот метод был вызван.

+0

+1 за отличную идею. Спасибо, товарищ – MSI

+0

Кто-то дает ему больше бонусов, пожалуйста, за хороший пример и разъяснения – MSI

Смежные вопросы