Откуда вы знаете, что тестировать при написании модульных тестов?[закрыто]

StackOverflow https://stackoverflow.com/questions/62625

  •  09-06-2019
  •  | 
  •  

Вопрос

Используя C #, мне нужен класс с именем User в котором есть имя пользователя, пароль, активный флаг, имя, фамилия, ФИО и т.д.

Должны быть методы, позволяющие аутентификация и Сохранить пользователь.Могу ли я просто написать тест для этих методов?И нужно ли мне вообще беспокоиться о тестировании свойств, поскольку они есть.Получатели и установщики Net?

Это было полезно?

Решение

Много замечательных ответов на этот вопрос есть и на мой вопрос:"Начинающиеся проблемы с TDD?Решения?Рекомендации?"

Могу я также порекомендовать взглянуть на мой запись в блоге (который был частично вдохновлен моим вопросом), я получил несколько хороших отзывов по этому поводу.А именно:

Я не знаю, с чего начать?

  • Начни все сначала.Думайте о написании тестов только тогда, когда вы пишете новый код.Это может быть переработка старого кода или совершенно новая функция.
  • Начните с простого.Не убегайте и не пытайтесь прийти в себя фреймворк для тестирования, а также быть в стиле TDD.Отладка.Утверждение работает нормально.Используйте это как отправную точку.Это не вмешивается в ваш проект и не создает зависимостей.
  • Начните с позитива.Вы пытаетесь улучшить свое ремесло, чувствуйте себя хорошо по этому поводу .Я видел много разработчиков , которые рады стагнации и не пробуют что-то новое, чтобы улучшить себя .Вы поступаете правильно помните об этом, и это поможет не дать вам сдаться.
  • Будьте готовы к испытаниям.Довольно сложно начать заниматься тестированием.Ожидайте трудностей, но помните – трудности можно преодолеть.

Проверяйте только На То, Что вы Ожидаете

У меня были реальные проблемы, когда я только начинал потому что я постоянно сидел там, пытаясь выяснить каждую возможную проблему, которая могла возникнуть, а затем пытался протестировать ее и исправить.Это быстрый способ избавиться от головной боли.Тестирование должно быть настоящим процессом YAGNI .Если вы знаете, что есть проблема , напишите тест для нее.В противном случае, не беспокойтесь.

Проверьте только одну Вещь

Каждый тестовый пример должен проверять только одну вещь.Если вы когда-нибудь поймаете себя на том, что ставите "и” в названии тестового примера, вы делаете что-то не так.

Я надеюсь, это означает, что мы можем перейти от "добытчиков и сеттеров" :)

Другие советы

Тестируйте свой код, а не язык.

Модульный тест, подобный:

Integer i = new Integer(7);
assert (i.instanceOf(integer));

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

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

Это привело меня к модульному тестированию, и это сделало меня очень счастливым

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

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

Я просто не знал, с чего начать кодирование, так как существовало так много различных вариантов оплаты.Счет-фактура может составлять 100 долларов, но клиент перевел только 99 долларов.Возможно, вы отправили счета-фактуры клиенту, но вы также совершили покупку у этого клиента.Итак, вы продали его за 300 долларов, но купили за 100.Вы можете ожидать, что ваш клиент заплатит вам 200 долларов за погашение остатка.А что, если вы продали за 500 долларов, но клиент заплатил вам всего 250 долларов?

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

Вот тут-то на помощь и пришло модульное тестирование.

Я начал писать (внутри тестового кода) метод для создания списка счетов-фактур, как для продаж, так и для покупок.Затем я написал второй метод для создания фактического платежа.Обычно пользователь вводит эту информацию через пользовательский интерфейс.

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

После выполнения теста я заходил в базу данных и дважды проверял, есть ли там то, что я ожидал.

После Я написал тест, я начал кодировать способ оплаты (часть класса BankHeader).В процессе кодирования я потрудился с кодом только для того, чтобы сделать первый тестовый проход.Я еще не думал о других, более сложных сценариях.

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

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

Проверяя корректность с помощью скидки при оплате, я также протестировал простой платеж.Оба теста, конечно, должны быть пройдены.

Затем я перешел к более сложным сценариям.

1) Придумайте новый сценарий

2) Напишите тест для этого сценария

3) Запустите этот единственный тест, чтобы увидеть, пройдет ли он

4) Если бы этого не произошло, я бы отлаживал и модифицировал код до тех пор, пока он не пройдет.

5) Изменяя код, я продолжал запускать все тесты

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

Я уверен, что использование модульного тестирования сэкономило мне несколько дней (или недель) кодирования и более или менее гарантирует корректность моего метода.

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

Да, даже в протестированном коде все еще могут быть ошибки, если пользователь делает то, о чем вы не подумали или помешали ему сделать

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

public class TestPayments
{
    InvoiceDiaryHeader invoiceHeader = null;
    InvoiceDiaryDetail invoiceDetail = null;
    BankCashDiaryHeader bankHeader = null;
    BankCashDiaryDetail bankDetail = null;



    public InvoiceDiaryHeader CreateSales(string amountIncVat, bool sales, int invoiceNumber, string date)
    {
        ......
        ......
    }

    public BankCashDiaryHeader CreateMultiplePayments(IList<InvoiceDiaryHeader> invoices, int headerNumber, decimal amount, decimal discount)
    {
       ......
       ......
       ......
    }


    [TestMethod]
    public void TestSingleSalesPaymentNoDiscount()
    {
        IList<InvoiceDiaryHeader> list = new List<InvoiceDiaryHeader>();
        list.Add(CreateSales("119", true, 1, "01-09-2008"));
        bankHeader = CreateMultiplePayments(list, 1, 119.00M, 0);
        bankHeader.Save();

        Assert.AreEqual(1, bankHeader.BankCashDetails.Count);
        Assert.AreEqual(1, bankHeader.BankCashDetails[0].Payments.Count);
        Assert.AreEqual(119M, bankHeader.BankCashDetails[0].Payments[0].PaymentAmount);
        Assert.AreEqual(0M, bankHeader.BankCashDetails[0].Payments[0].PaymentDiscount);
        Assert.AreEqual(0, bankHeader.BankCashDetails[0].Payments[0].InvoiceHeader.Balance);
    }

    [TestMethod]
    public void TestSingleSalesPaymentDiscount()
    {
        IList<InvoiceDiaryHeader> list = new List<InvoiceDiaryHeader>();
        list.Add(CreateSales("119", true, 2, "01-09-2008"));
        bankHeader = CreateMultiplePayments(list, 2, 118.00M, 1M);
        bankHeader.Save();

        Assert.AreEqual(1, bankHeader.BankCashDetails.Count);
        Assert.AreEqual(1, bankHeader.BankCashDetails[0].Payments.Count);
        Assert.AreEqual(118M, bankHeader.BankCashDetails[0].Payments[0].PaymentAmount);
        Assert.AreEqual(1M, bankHeader.BankCashDetails[0].Payments[0].PaymentDiscount);
        Assert.AreEqual(0, bankHeader.BankCashDetails[0].Payments[0].InvoiceHeader.Balance);
    }

    [TestMethod]
    [ExpectedException(typeof(ApplicationException))]
    public void TestDuplicateInvoiceNumber()
    {
        IList<InvoiceDiaryHeader> list = new List<InvoiceDiaryHeader>();
        list.Add(CreateSales("100", true, 2, "01-09-2008"));
        list.Add(CreateSales("200", true, 2, "01-09-2008"));

        bankHeader = CreateMultiplePayments(list, 3, 300, 0);
        bankHeader.Save();
        Assert.Fail("expected an ApplicationException");
    }

    [TestMethod]
    public void TestMultipleSalesPaymentWithPaymentDiscount()
    {
        IList<InvoiceDiaryHeader> list = new List<InvoiceDiaryHeader>();
        list.Add(CreateSales("119", true, 11, "01-09-2008"));
        list.Add(CreateSales("400", true, 12, "02-09-2008"));
        list.Add(CreateSales("600", true, 13, "03-09-2008"));
        list.Add(CreateSales("25,40", true, 14, "04-09-2008"));

        bankHeader = CreateMultiplePayments(list, 5, 1144.00M, 0.40M);
        bankHeader.Save();

        Assert.AreEqual(1, bankHeader.BankCashDetails.Count);
        Assert.AreEqual(4, bankHeader.BankCashDetails[0].Payments.Count);
        Assert.AreEqual(118.60M, bankHeader.BankCashDetails[0].Payments[0].PaymentAmount);
        Assert.AreEqual(400, bankHeader.BankCashDetails[0].Payments[1].PaymentAmount);
        Assert.AreEqual(600, bankHeader.BankCashDetails[0].Payments[2].PaymentAmount);
        Assert.AreEqual(25.40M, bankHeader.BankCashDetails[0].Payments[3].PaymentAmount);

        Assert.AreEqual(0.40M, bankHeader.BankCashDetails[0].Payments[0].PaymentDiscount);
        Assert.AreEqual(0, bankHeader.BankCashDetails[0].Payments[1].PaymentDiscount);
        Assert.AreEqual(0, bankHeader.BankCashDetails[0].Payments[2].PaymentDiscount);
        Assert.AreEqual(0, bankHeader.BankCashDetails[0].Payments[3].PaymentDiscount);

        Assert.AreEqual(0, bankHeader.BankCashDetails[0].Payments[0].InvoiceHeader.Balance);
        Assert.AreEqual(0, bankHeader.BankCashDetails[0].Payments[1].InvoiceHeader.Balance);
        Assert.AreEqual(0, bankHeader.BankCashDetails[0].Payments[2].InvoiceHeader.Balance);
        Assert.AreEqual(0, bankHeader.BankCashDetails[0].Payments[3].InvoiceHeader.Balance);
    }

    [TestMethod]
    public void TestSettlement()
    {
        IList<InvoiceDiaryHeader> list = new List<InvoiceDiaryHeader>();
        list.Add(CreateSales("300", true, 43, "01-09-2008")); //Sales
        list.Add(CreateSales("100", false, 6453, "02-09-2008")); //Purchase

        bankHeader = CreateMultiplePayments(list, 22, 200, 0);
        bankHeader.Save();

        Assert.AreEqual(1, bankHeader.BankCashDetails.Count);
        Assert.AreEqual(2, bankHeader.BankCashDetails[0].Payments.Count);
        Assert.AreEqual(300, bankHeader.BankCashDetails[0].Payments[0].PaymentAmount);
        Assert.AreEqual(-100, bankHeader.BankCashDetails[0].Payments[1].PaymentAmount);
        Assert.AreEqual(0, bankHeader.BankCashDetails[0].Payments[0].InvoiceHeader.Balance);
        Assert.AreEqual(0, bankHeader.BankCashDetails[0].Payments[1].InvoiceHeader.Balance);
    }

Если они действительно тривиальны, то не утруждайте себя тестированием.Например, если они реализованы следующим образом;

public class User
{
    public string Username { get; set; }
    public string Password { get; set; }
}

Если, с другой стороны, вы делаете что-то умное (например, шифруете и дешифруете пароль в программе получения / установки), то проведите тест.

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

Этот вопрос, по-видимому, заключается в том, где можно провести черту между тем, какие методы тестируются, а какие нет.

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

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

Возможно, другой член команды расширил методы set / get, включив в них логику, которая теперь нуждается в тестировании, но затем не создавала тесты.Но теперь ваш код вызывает эти методы, и вы не знаете, что они изменились и нуждаются в углубленном тестировании, а тестирование, которое вы проводите в области разработки и контроля качества, не вызывает дефекта, но реальные бизнес-данные в первый день выпуска вызывают его.

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

Мое мнение таково, что несколько минут "потраченного впустую" времени, охватывающего ВСЕ методы модульными тестами, даже тривиальными, могут избавить от нескольких дней головной боли в будущем, потери денег / репутации бизнеса и потери чьей-либо работы.

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

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

Еще один канонический ответ.Это, я полагаю, от Рона Джеффриса:

Тестируйте только тот код, с которым вы хотите работать.

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

Если вы занимаетесь разработкой на основе тестирования, вам следует сначала написать контракт (например, интерфейс), а затем написать тесты для использования этого интерфейса, которые документируют ожидаемые результаты / поведение. Тогда пишите свои методы сами, не касаясь кода в ваших модульных тестах.Наконец, возьмите инструмент покрытия кода и убедитесь, что ваши тесты используют все логические пути в вашем коде.

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

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

Вы должны протестировать все.Прямо сейчас у вас есть геттеры и сеттеры, но однажды вы можете их несколько изменить, возможно, для выполнения проверки или чего-то еще.Тесты, которые вы напишете сегодня, будут использованы завтра, чтобы убедиться, что все продолжает работать в обычном режиме.Когда вы пишете тест, вы должны забыть о таких соображениях, как "прямо сейчас это тривиально".В гибком или управляемом тестированием контексте вы должны тестировать, предполагая будущий рефакторинг.Кроме того, вы пробовали вводить действительно странные значения, такие как чрезвычайно длинные строки или другой "плохой" контент?Что ж, так и должно быть...никогда не предполагайте, насколько сильно ваш код может быть подвергнут злоупотреблениям в будущем.

Как правило, я нахожу, что написание обширных пользовательских тестов, с одной стороны, утомительно.С другой стороны, это всегда дает вам бесценное представление о том, как должно работать ваше приложение, и помогает отбросить простые (и ложные) предположения (например:длина имени пользователя всегда будет меньше 1000 символов).

Для простых модулей, которые могут оказаться в наборе инструментов или в проекте с открытым исходным кодом, вы должны протестировать как можно больше, включая тривиальные методы получения и установки.Вещь, которую вы должны иметь в виду, заключается в том, что генерация модульного теста при написании конкретного модуля довольно проста и прямолинейна.Добавление геттеров и сеттеров требует минимального кода и может быть обработано без особых раздумий.Однако, как только ваш код будет размещен в более крупной системе, эти дополнительные усилия могут защитить вас от изменений в базовой системе, таких как изменения типа в базовом классе.Тестирование everthing - лучший способ получить завершенную регрессию.

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

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

В иерархиях наследования обязательно проверьте наличие LSP соблюдение требований.

Тестирование геттеров и установщиков по умолчанию кажется мне не очень полезным, если только вы не планируете провести некоторую проверку позже.

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

Если методы аутентификации и сохранения используют свойства, то ваши тесты будут косвенно касаться этих свойств.Пока свойства просто предоставляют доступ к данным, то явное тестирование не должно быть необходимым (если только вы не хотите получить 100% покрытие).

Я бы проверил ваши геттеры и сеттеры.В зависимости от того, кто пишет код, некоторые люди меняют значение методов получения / установки.Я видел инициализацию переменных и другую проверку как часть методов получения.Чтобы протестировать подобные вещи, вы бы хотели, чтобы модульные тесты явно охватывали этот код.

Лично я бы "протестировал все, что может сломаться", и простой геттер (или даже лучшие автоматические свойства) не сломался.У меня никогда не было сбоя простого оператора return, и поэтому у меня никогда не было теста для них.Если в геттерах есть вычисления внутри них или какая-то другая форма операторов, я бы, конечно, добавил для них тесты.

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

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

В случае простых целых чисел это также применимо - что произойдет, если вы передадите long вместо integer ?Вот причина, по которой вы пишете UT :)

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

Вы должны протестировать "каждый нетривиальный блок кода", используя модульные тесты, насколько это возможно.

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

Ваши методы Authenticate() и Save() выглядят хорошими кандидатами для тестирования.

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

Написание тестов после этого гораздо более болезненно, но выполнимо.

Вот что бы я сделал на вашем месте:

  1. Напишите базовый набор тестов, которые проверяют основную функцию.
  2. Получите NCover и запустите его в своих тестах.На данный момент охват вашего тестирования, вероятно, составит около 50%.
  3. Продолжайте добавлять тесты, охватывающие ваши крайние случаи, пока не получите охват около 80% -90%

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

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

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

Не тестируйте явно работающий (шаблонный) код.Так что, если ваши установщики и получатели - это просто "propertyvalue = value" и "return propertyvalue", нет смысла это тестировать.

Даже get / set могут иметь странные последствия, в зависимости от того, как они были реализованы, поэтому их следует рассматривать как методы.

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

Вам также необходимо знать о подводных камнях безопасности, таких как, например, SQL-инъекция, и протестировать их.

Так что да, вам действительно нужно побеспокоиться о тестировании свойств.

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

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

Как правило, любую логику, которую я пишу и которая имеет какую-либо бизнес-логику, я помещаю внутри другого уровня или бизнес-логики layer.

Тогда легко писать тесты для всего, что что-то делает.

Первый проход - напишите модульный тест для каждого общедоступного метода на вашем "Уровне бизнес-логики".

Если бы у меня был такой класс, как этот:

   public class AccountService
    {
        public void DebitAccount(int accountNumber, double amount)
        {

        }

        public void CreditAccount(int accountNumber, double amount)
        {

        }

        public void CloseAccount(int accountNumber)
        {

        }
    }

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

   [TestFixture]
    public class AccountServiceTests
    {
        [Test]
        public void DebitAccountTest()
        {

        }

        [Test]
        public void CreditAccountTest()
        {

        }

        [Test]
        public void CloseAccountTest()
        {

        }
    }

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

Есть много других подходов, которые вы можете использовать, а именно Behavioir Driven Development (BDD), которые более сложны и не самое лучшее место для начала с вашими навыками модульного тестирования.

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

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

Я рекомендую TestDriven.Net или Перетачиватель поскольку оба они легко интегрируются в Visual Studio.

что ж, если вы думаете, что он может сломаться, напишите для него тест.Обычно я не тестирую setter / getter, но давайте предположим, что вы создаете его для User.Name , которые объединяют имя и фамилию, я бы написал тест, чтобы, если кто-то изменит порядок следования фамилии и отчества, по крайней мере, он знал, что изменил что-то, что было протестировано.

Канонический ответ - "протестируйте все, что может сломаться". Если вы уверены, что свойства не сломаются, не тестируйте их.

И как только обнаруживается, что что-то сломалось (вы обнаруживаете ошибку), очевидно, это означает, что вам нужно это протестировать.Напишите тест для воспроизведения ошибки, посмотрите, как он завершается неудачей, затем исправьте ошибку, затем посмотрите, как тест проходит успешно.

Я бы порекомендовал написать несколько тестов для ваших методов аутентификации и сохранения.В дополнение к случаю успеха (где указаны все параметры, все правильно прописано и т.д.), Полезно иметь тесты для различных случаев сбоя (неправильные или отсутствующие параметры, недоступные подключения к базе данных, если применимо, и т.д.).Я рекомендую Прагматичное модульное тестирование в C # с помощью NUnit в качестве ориентира.

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

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

Код с большим количеством тестов, но небольшим охватом, не был хорошо протестирован.Тем не менее, код со 100% покрытием, но без тестирования границ и ошибок, также невелик.

Вам нужен баланс между высоким охватом (минимум 90%) и переменными входными данными.

Не забудьте проверить наличие "мусора внутри"!

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

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

Это делает наш код лучше...точка!

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

В истинном духе модульного тестирования эти тесты являются нет в первую очередь для того, чтобы "протестировать" больше нашего кода;или получить лучшее покрытие кода на 90-100%.Это все дополнительные преимущества о том, чтобы сначала написать тесты.Большой выигрыш заключается в том, что наш производственный код в конечном итоге пишется намного лучше благодаря естественному процессу TDD.

Чтобы лучше донести эту идею, следующее может быть полезно при чтении:

Ошибочная теория модульных тестов
Целенаправленная разработка программного обеспечения

Если мы чувствуем, что акт написания дополнительные модульные тесты это то, что помогает нам получать продукт более высокого качества, тогда мы, возможно, страдаем от Культ Груза разработки, основанной на тестировании.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top