Должен ли я изменить соглашение об именах для моих модульных тестов? - PullRequest
11 голосов
/ 19 июня 2009

В настоящее время я использую простое соглашение для своих модульных тестов. Если у меня есть класс с именем «EmployeeReader», я создаю тестовый класс с именем «EmployeeReader.Tests. Затем я создаю все тесты для класса в тестовом классе с именами, такими как:

  • Reading_Valid_Employee_Data_Correctly_Generates_Employee_Object
  • Reading_Missing_Employee_Data_Throws_Invalid_Employee_ID_Exception

и т. Д.

Недавно я читал о различном типе именования , используемом в BDD. Мне нравится удобочитаемость этого наименования, в результате чего список тестов выглядит примерно так:

  • When_Reading_Valid_Employee (фиксатор)
    • Employee_Object_Is_Generated (метод)
    • Employee_Has_Correct_ID (метод)
  • When_Reading_Missing_Employee (приспособление)
    • An_Invalid_Employee_ID_Exception_Is_Thrown (метод)

и т. Д.

Кто-нибудь использовал оба стиля именования? Можете ли вы дать какие-либо советы, преимущества, недостатки, ошибки и т. Д., Чтобы помочь мне принять решение о переходе на следующий проект или нет?

Ответы [ 7 ]

6 голосов
/ 19 июня 2009

Соглашение об именах, которое я использовал:

functionName_shouldDoThis_whenThisIsTheSituation

Например, это будут некоторые имена тестов для функции pop в стеке

pop_shouldThrowEmptyStackException_whenTheStackIsEmpty

pop_shouldReturnTheObjectOnTheTopOfTheStack_whenThereIsAnObjectOnTheStack

3 голосов
/ 19 июня 2009

Ваш второй пример (наличие фиксатора для каждой логической «задачи», а не одного для каждого класса) имеет преимущество в том, что вы можете иметь различную логику SetUp и TearDown для каждой задачи, упрощая тем самым ваши индивидуальные методы тестирования и делая их более читаемый.

Вам не нужно соглашаться на то или другое в качестве стандарта. Мы используем смесь обоих, в зависимости от того, сколько разных «заданий» мы должны тестировать для каждого класса.

2 голосов
/ 19 июня 2009

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

1 голос
/ 21 августа 2009

Я прошел две дороги, которые вы описываете в своем вопросе, а также несколько других ... Ваша первая альтернатива довольно проста и проста для понимания большинством людей. Мне лично больше нравится стиль BDD (ваш второй пример), потому что он изолирует различные контексты и группирует наблюдения в этих контекстах. Единственным недостатком является то, что он генерирует больше кода, поэтому начинать делать это будет немного громоздко, пока не увидите аккуратные тесты. Кроме того, если вы используете наследование для повторного использования настройки прибора, вам нужен тестовый прогон, который выводит цепочку наследования. Рассмотрим класс "An_empty_stack", и вы хотите использовать его повторно, поэтому затем вы делаете другой класс: Если ваш testrunner не поддерживает это, ваши тесты будут содержать избыточную информацию, такую ​​как: «When_five_is_pressed_on_empty_stack: An_empty_stack», чтобы вывод был приятным.

1 голос
/ 27 июля 2009

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

По сути, тестовые классы - это контексты, которые могут быть вложенными, а методы - это утверждения в одну строку. Например,

public class MyClassSpecification
{
    protected MyClass instance = new MyClass();

    public class When_foobar_is_42 : MyClassSpecification 
    {
        public When_foobar_is_42() {
            this.instance.SetFoobar( 42 ); 
        }

        public class GetAnswer : When_foobar_is_42
        {
            private Int32 result;

            public GetAnswer() {
                this.result = this.GetAnswer();
            }

            public void should_return_42() {
                Assert.AreEqual( 42, result );
            }
        }
    }
}

, который даст мне следующий вывод в моем тестовом бегуне:

MyClassSpecification+When_foobar_is_42+GetAnswer
    should_return_42
1 голос
/ 03 июля 2009

Часть обоснования 2-го соглашения об именах, на которое вы ссылаетесь, заключается в том, что вы создаете тесты и поведенческие спецификации одновременно. Вы устанавливаете контекст, в котором происходит что-то, и что в действительности должно происходить в этом контексте. (По моему опыту, наблюдения / методы испытаний часто начинаются с "should_", поэтому вы получаете стандартный формат "When_the_invoicing_system_is_told_to_email_the_client", "should_initiate_connection_to_mail_server".)

Существуют инструменты, которые будут отражать ваши тестовые данные и выводить красиво отформатированный HTML-лист спецификации, удаляя подчеркивания. В итоге вы получите удобочитаемую документацию, которая синхронизируется с реальным кодом (при условии, что ваш тестовый охват будет высоким и точным).

В зависимости от истории / функции / подсистемы, над которой вы работаете, эти спецификации могут быть показаны и поняты заинтересованным сторонам, не являющимся программистами, для проверки и обратной связи, что лежит в основе гибкой и BDD в частности.

0 голосов
/ 03 июля 2009

я голосую за вызов класса тестового случая: EmployeeReaderTestCase и вызов методов (), таких как http://xunitpatterns.com/Organization.html и http://xunitpatterns.com/Organization.html#Test%20Naming%20Conventions

...