Используя C#, мне нужен класс User, который имеет имя пользователя, пароль, активный флаг, имя, фамилию, полное имя и т. д.
Должны быть методы для подтверждать подлинность и спасти пользователя. Я просто напишу тест по методам? И нужно ли мне вообще беспокоиться о тестировании свойств, поскольку они являются геттерами и сеттерами .Net?
Помните, что пароли не должны храниться в виде открытого текста.





Я не могу говорить конкретно о C#, но когда я пишу модульные тесты, я тестирую КАЖДЫЙ ввод, даже те, которые не выполняет пользователь, поэтому я знаю, как предотвратить свои собственные ошибки.
Правило состоит в том, что вы должны проверять каждую написанную вами логику. Если вы реализовали какую-то конкретную функциональность в геттерах и сеттерах, я думаю, что их стоит протестировать. Если они присваивают значения только некоторым частным полям, не беспокойтесь.
Насколько я понимаю модульные тесты в контексте гибкой разработки, Майк, да, вам нужно протестировать геттеры и сеттеры (при условии, что они общедоступны). Вся концепция модульного тестирования состоит в том, чтобы протестировать программный модуль, который в данном случае является классом, как черный ящик. Поскольку геттеры и сеттеры видны извне, вам необходимо протестировать их вместе с Authenticate и Save.
Не помешает написать модульные тесты для ваших геттеров и сеттеров. Прямо сейчас они могут просто выполнять получение / набор полей под капотом, но в будущем у вас может быть логика проверки или зависимости между свойствами, которые необходимо протестировать. Легче написать его сейчас, когда вы думаете об этом, чем не забыть модернизировать его, если когда-нибудь придет такое время.
Что ж, если вашим геттерам / сеттерам нужны модульные тесты, с ними должна быть связана какая-то логика, так что это означает, что логика должна быть написана внутри них, если у них нет никакой логики, никаких модульных тестов писать не нужно.
Он считает, что логика к ним может быть добавлена позже.
Если методы Authenticate и Save используют свойства, тогда ваши тесты будут косвенно касаться свойств. Пока свойства просто предоставляют доступ к данным, явное тестирование не требуется (если вы не собираетесь на 100% покрытие).
Проверяйте свой код, а не язык.
Модульный тест вроде:
Integer i = new Integer(7);
assert (i.instanceOf(integer));
полезен только в том случае, если вы пишете компилятор и есть ненулевой шанс, что ваш метод instanceof не работает.
Не тестируйте то, что вы можете применить на языке. В вашем случае я бы сосредоточился на ваших методах аутентификации и сохранения - и я бы написал тесты, чтобы убедиться, что они могут корректно обрабатывать нулевые значения в любом или всех этих полях.
Хороший момент по поводу «Не тестируйте фреймворк» - кое-что, что я тоже получил, когда впервые в этом был. +1 :)
Я бы протестировал ваши геттеры и сеттеры. В зависимости от того, кто пишет код, некоторые люди меняют значение методов получения / установки. Я видел инициализацию переменных и другие проверки как часть методов получения. Чтобы протестировать такие вещи, вам нужны модульные тесты, явно охватывающие этот код.
Лично я бы «протестировал все, что может сломаться», и простой геттер (или даже лучше автоматические свойства) не сломается. У меня никогда не было ошибок простого оператора return, и поэтому я никогда не проверял их. Если у геттеров есть вычисления внутри них или какая-то другая форма операторов, я бы обязательно добавил для них тесты.
Лично я использую Moq в качестве фреймворка фиктивных объектов, а затем проверяю, что мой объект вызывает окружающие объекты так, как должен.
Вы должны покрыть выполнение каждого метода класса с помощью UT и проверить возвращаемое значение метода. Сюда входят методы получения и установки, особенно в случае, если члены (свойства) являются сложными классами, что требует выделения большого объема памяти во время их инициализации. Вызовите сеттер, например, с какой-нибудь очень большой строкой (или чем-то с греческими символами) и убедитесь, что результат правильный (не усеченный, кодировка хорошая и т. д.)
В случае простых целых чисел это также применимо - что произойдет, если вы передадите long вместо integer? Вот почему вы пишете UT :)
Если они действительно тривиальны, то не беспокойтесь о тестировании. Например, если они реализованы таким образом;
public class User
{
public string Username { get; set; }
public string Password { get; set; }
}
Если, с другой стороны, вы делаете что-то умное (например, шифруете и расшифровываете пароль в геттере / сеттере), то проверьте это.
Тестирование класса должно подтвердить, что:
Конечно, если геттеры и сеттеры не имеют специальной логики, тогда тесты методов Authenticate иSave должны охватывать их, но в противном случае должен быть написан явный тест.
Я бы не стал тестировать фактическую настройку свойств. Я был бы больше озабочен тем, как эти свойства заполняются потребителем и чем они их заполняют. При любом тестировании вы должны взвесить риски со временем / стоимостью тестирования.
Вы должны тестировать «каждый нетривиальный блок кода», используя модульные тесты, насколько это возможно.
Если ваши свойства тривиальны и маловероятно, что кто-то внесет в них ошибку, то их следует безопасно не тестировать.
Ваши методы Authenticate () и Save () выглядят хорошими кандидатами для тестирования.
Тестирование стандартного кода - пустая трата времени, но, как говорит Славо, если вы добавите побочный эффект к своим геттерам / сеттерам, вам следует написать тест, чтобы сопровождать эту функциональность.
Если вы занимаетесь разработкой, управляемой тестированием, вы должны сначала написать контракт (например, интерфейс), а затем написать тест (ы) для проверки этого интерфейса, который документирует ожидаемые результаты / поведение. потом сами пишите свои методы, не трогая код в своих модульных тестах. Наконец, возьмите инструмент покрытия кода и убедитесь, что ваши тесты проверяют все логические пути в вашем коде.
В идеале вы бы выполнили свои модульные тесты во время написания класса. Вот как вы должны это делать при использовании разработки через тестирование. Вы добавляете тесты по мере реализации каждой функциональной точки, убедившись, что вы также покрываете крайние случаи с помощью test.
Писать тесты потом гораздо труднее, но выполнимо.
Вот что я бы сделал на вашем месте:
Это должно дать вам хороший рабочий набор модульных тестов, которые будут служить хорошим буфером против регрессий.
Единственная проблема с этим подходом заключается в том, что код должен быть разработан, чтобы его можно было тестировать таким образом. Если вы на раннем этапе допустили какие-либо ошибки сопряжения, вам не удастся очень легко получить высокий охват.
Вот почему так важно писать тесты перед написанием кода. Это заставляет вас писать слабо связанный код.
Не тестируйте заведомо рабочий (шаблонный) код. Поэтому, если ваши сеттеры и геттеры - это просто «propertyvalue = value» и «return propertyvalue», нет смысла проверять это.
Даже get / set могут иметь странные последствия в зависимости от того, как они были реализованы, поэтому их следует рассматривать как методы.
Каждый из них должен будет указать наборы параметров для свойств, определяя как приемлемые, так и неприемлемые свойства, чтобы гарантировать, что вызовы возвращаются / завершаются ошибкой ожидаемым образом.
Вам также необходимо знать о подводных камнях безопасности, например о SQL-инъекции, и проверять их.
Так что да, вам нужно побеспокоиться о тестировании свойств.
Действительно тривиальный код, такой как методы получения и установки, который не имеет дополнительного поведения, кроме установки частного поля, является излишним для тестирования. В 3.0 C# даже есть некоторый синтаксический сахар, где компилятор заботится о закрытом поле, поэтому вам не нужно его программировать.
Обычно я пишу множество очень простых тестов, проверяющих поведение, которое я ожидаю от своих классов. Даже если это простые вещи вроде сложения двух чисел. Я часто переключаюсь между написанием простого теста и написанием нескольких строк кода. Причина этого в том, что я могу изменить код, не опасаясь, что сломал то, о чем не думал.
Рад, что вы хорошо изложили принцип KISS .. У меня часто есть тесты, которые буквально похожи на 2-3 строки кода, настоящие маленькие, простые тесты. Легко грок и трудно сломать :) +1
в общем, когда метод определен только для определенных значений, проверьте значения на и более границе того, что является приемлемым. Другими словами, убедитесь, что ваш метод выполняет то, что должен делать, но не более. Это важно, потому что, когда вы собираетесь потерпеть неудачу, вы хотите потерпеть неудачу раньше.
В иерархиях наследования обязательно проверьте соответствие LSP.
Тестирование геттеров и сеттеров по умолчанию не кажется мне очень полезным, если вы не планируете провести некоторую проверку позже.
Я считаю, что глупо тестировать геттеры и сеттеры, когда они выполняют только простую операцию. Лично я не пишу сложные модульные тесты, чтобы охватить какой-либо шаблон использования. Я стараюсь написать достаточно тестов, чтобы убедиться, что я справился с нормальным поведением при выполнении и как можно больше случаев ошибок. Я напишу больше модульных тестов в ответ на сообщения об ошибках. Я использую модульный тест, чтобы убедиться, что код соответствует требованиям и упростить будущие модификации. Я чувствую себя гораздо более склонным к изменению кода, когда знаю, что если я что-то сломаю, тест не удастся.
На мой вопрос: "Начало TDD - Проблемы? Решения? Рекомендации?" много замечательных ответов.
Могу я также порекомендовать взглянуть на мой Сообщение блога (который частично был вдохновлен моим вопросом), у меня есть хорошие отзывы по этому поводу. А именно:
I Don’t Know Where to Start?
- Start afresh. Only think about writing tests when you are writing new code. This can be re-working of old code, or a completely new feature.
- Start simple. Don’t go running off and trying to get your head round a testing framework as well as being TDD-esque. Debug.Assert works fine. Use it as a starting point. It doesn’t mess with your project or create dependencies.
- Start positive. You are trying to improve your craft, feel good about it. I have seen plenty of developers out there that are happy to stagnate and not try new things to better themselves. You are doing the right thing, remember this and it will help stop you from giving up.
- Start ready for a challenge. It is quite hard to start getting into testing. Expect a challenge, but remember – challenges can be overcome.
Only Test For What You Expect
I had real problems when I first started because I was constantly sat there trying to figure out every possible problem that could occur and then trying to test for it and fix. This is a quick way to a headache. Testing should be a real YAGNI process. If you know there is a problem, then write a test for it. Otherwise, don’t bother.
Only Test One Thing
Each test case should only ever test one thing. If you ever find yourself putting “and” in the test case name, you’re doing something wrong.
Надеюсь, это означает, что мы можем уйти от "геттеров и сеттеров" :)
«Если вы знаете, что есть проблема, напишите для нее тест. В противном случае не беспокойтесь». Я бы не согласился с такой формулировкой. У меня сложилось впечатление, что модульные тесты должны охватывать все возможные пути выполнения.
Хотя некоторые могут выступать за такие вещи, я лично этого не делаю. Добрые 90% моей головной боли возникали из-за того, что я просто пытался делать «все». Я говорю: проверьте то, чего вы ожидаете (чтобы вы знали, что получаете обратно правильные значения), но не пытайтесь во всем этом разобраться. ЯГНИ.
Я тоже сторонник подхода «проверьте свои ошибки». Если бы у всех нас было бесконечное время и терпение, мы бы протестировали все возможные пути выполнения. Но мы этого не делаем, поэтому вы должны направить свои усилия туда, где это будет иметь наибольший эффект.
Я бы написал тест для всего, что вы пишете, для чего можно тестировать вне графического интерфейса.
Как правило, любую написанную мной логику, имеющую любую бизнес-логику, я помещаю на другой уровень или уровень бизнес-логики.
Тогда написать тесты для чего-либо, что что-то делает, будет легко.
Сначала напишите модульный тест для каждого общедоступного метода на «уровне бизнес-логики».
Если бы у меня был такой класс:
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()
{
}
}
Напишите свои тесты, чтобы проверить код, который вы написали, чтобы что-то сделать. Если вы повторяете набор вещей и что-то меняете в каждой из них, напишите тест, который делает то же самое, и подтвердите, что действительно произошло.
Есть много других подходов, которые вы можете использовать, а именно Behavoir Driven Development (BDD), которые более сложны и не являются отличным местом для начала ваших навыков модульного тестирования.
Итак, мораль этой истории такова: тестируйте все, что делает то, о чем вы могли бы беспокоиться, продолжайте модульные тесты тестировать конкретные вещи небольшого размера, многие тесты хороши.
Держите свою бизнес-логику за пределами уровня пользовательского интерфейса, чтобы вы могли легко писать для них тесты, и все будет хорошо.
Я рекомендую TestDriven.Net или ReSharper, поскольку оба легко интегрируются в Visual Studio.
хорошо, если вы думаете, что он может сломаться, напишите для него тест. Я обычно не тестирую сеттер / получатель, но позволяет вам сделать его для User.Name, который объединяет имя и фамилию, я бы написал тест, чтобы, если кто-то изменит порядок для фамилии и имени, по крайней мере, он будет знать он изменил то, что было проверено.
Канонический ответ - «тестируйте все, что может сломаться». Если вы уверены, что свойства не сломаются, не проверяйте их.
И как только обнаруживается, что что-то сломалось (вы обнаруживаете ошибку), это, очевидно, означает, что вам нужно проверить это. Напишите тест, чтобы воспроизвести ошибку, посмотрите, как он не работает, затем исправьте ошибку, затем посмотрите, как проходит тест.
Вы должны все протестировать. Прямо сейчас у вас есть геттеры и сеттеры, но однажды вы можете их немного изменить, возможно, для проверки или чего-то еще. Тесты, которые вы напишете сегодня, будут использованы завтра, чтобы убедиться, что все работает как обычно. Когда вы пишете тест, вы должны забыть о таких соображениях, как «сейчас это тривиально». В контексте гибкой разработки или тестирования вы должны протестировать, предполагая будущий рефакторинг. Кроме того, вы пробовали вводить действительно странные значения, такие как очень длинные строки или другой «плохой» контент? Что ж, вы должны ... никогда не предполагать, насколько серьезно ваш код может быть использован в будущем.
Обычно я считаю, что написание обширных пользовательских тестов утомительно, с одной стороны. С другой стороны, хотя он всегда дает вам бесценное представление о том, как должно работать ваше приложение, и помогает отбросить простые (и ложные) предположения (например: имя пользователя всегда будет меньше 1000 символов в длину).
Я бы рекомендовал написать несколько тестов для ваших методов аутентификации и сохранения. В дополнение к успешному случаю (когда все параметры указаны, все написано правильно и т. д.), Хорошо иметь тесты для различных случаев сбоя (неверные или отсутствующие параметры, недоступные соединения с базой данных, если применимо, и т. д.). Я рекомендую Прагматическое модульное тестирование на C# с NUnit как ссылку.
Как утверждали другие, модульные тесты для геттеров и сеттеров излишни, если в ваших геттерах и сеттерах нет условной логики.
Для простых модулей, которые могут оказаться в наборе инструментов или в проекте с открытым исходным кодом, вы должны протестировать как можно больше, включая тривиальные методы получения и установки. Вы должны иметь в виду, что создание модульного теста при написании конкретного модуля довольно просто и понятно. Добавление геттеров и сеттеров - это минимальный код, с которым можно легко справиться. Однако, как только ваш код будет помещен в более крупную систему, эти дополнительные усилия могут защитить вас от изменений в базовой системе, таких как изменения типа в базовом классе. Тестирование всего - лучший способ добиться полной регрессии.
Хотя можно правильно угадать, где ваш код нуждается в тестировании, я обычно думаю, что вам нужны метрики, чтобы подтвердить это предположение. На мой взгляд, модульное тестирование идет рука об руку с показателями покрытия кода.
Код с большим количеством тестов, но с небольшим охватом, не был хорошо протестирован. Тем не менее, код со 100% покрытием, но без проверки границ и случаев ошибок, тоже не очень хорош.
Вам нужен баланс между высоким охватом (минимум 90%) и переменными входными данными.
Не забудьте проверить "мусор в"!
Кроме того, модульный тест не является модульным тестом, если он не проверяет наличие сбоя. Модульные тесты, у которых нет утверждений или отмечены известными исключениями, просто проверят, что код не умирает при запуске!
Вам необходимо разработать свои тесты так, чтобы они всегда сообщали о сбоях или неожиданных / нежелательных данных!
Одна вещь, о которой мы, разработчики программного обеспечения, забываем, занимаясь разработкой через тестирование, - это цель наших действий. Если модульный тест пишется после того, как производственный код уже готов, значение теста сильно снижается (но не теряется полностью).
В истинном духе модульного тестирования эти тесты нет предназначены в первую очередь для «тестирования» большего количества нашего кода; или улучшить покрытие кода на 90% -100%. Это все дополнительные льготы написания тестов в первую очередь. Большим преимуществом является то, что наш производственный код будет написан намного лучше благодаря естественному процессу TDD.
Чтобы лучше донести эту идею, к прочтению может быть полезно прочитать следующее:
Ошибочная теория модульных тестов
Целенаправленная разработка программного обеспечения
Если мы чувствуем, что написание больше модульных тестов - это то, что помогает нам получить продукт более высокого качества, тогда мы можем страдать от Культ Карго разработки через тестирование.
Я не согласен с утверждением, что модульные тесты не имеют ценности после того, как производственный код уже готов. Такие утверждения не учитывают их полезность при воспроизведении условий ошибок, обнаруженных в производственной среде, или для понимания кода, унаследованного от предыдущего разработчика или команды.
Возможно, я ошибся. Я не имел в виду, что модульные тесты не имеют ценности после того, как готов производственный код. Однако их стоимость снижается. Самое большое преимущество модульного тестирования заключается в магии, которая возникает, когда мы позволяем им управлять нашей производственной разработкой.
У меня второй проверить все, что может сломаться и не пиши глупых тестов. Но наиболее важным принципом является проверьте все, что вы обнаружите, сломано: если какой-то метод ведет себя странно, напишите тест, чтобы выделить набор данных, который приводит к сбою, затем исправьте ошибку и посмотрите, как полоса станет зеленой. Также проверьте «граничные» значения данных (null, 0, MAX_INT, пустые списки и т. д.).
При написании модульных тестов или любого другого теста вы определяете, что тестировать, глядя на граничные условия того, что вы тестируете. Например, у вас есть функция is_prime. К счастью, он делает то, что подразумевает его название, и сообщает вам, является ли целочисленный объект простым или нет. Для этого я предполагаю, что вы используете объекты. Теперь нам нужно будет проверить, что действительные результаты получены для известного диапазона простых и не простых объектов. Это ваша отправная точка.
По сути, посмотрите, что должно произойти с функцией, методом, программой или скриптом, а затем на то, что определенно должно произойти нет с тем же кодом. Это основа для вашего теста. Просто будьте готовы изменить свои тесты по мере того, как вы станете более осведомленными о том, что должен происходит с вашим кодом.
Еще один канонический ответ. Это, как мне кажется, от Рона Джеффриса:
Only test the code that you want to work.
Написание кода, который не имеет ценности, всегда плохая идея. Поскольку предлагаемый тест не добавляет ценности вашему проекту (или очень близко к нему). Тогда вы тратите драгоценное время, которое можно потратить на написание кода, который действительно приносит пользу.
Это привело меня к модульному тестированию и очень обрадовало
Мы только начали проводить модульное тестирование. Долгое время я знал, что было бы хорошо начать этим заниматься, но я понятия не имел, с чего начать и, что более важно, что тестировать.
Затем нам пришлось переписать важный фрагмент кода нашей бухгалтерской программы. Эта часть была очень сложной, так как предполагала множество различных сценариев. Часть, о которой я говорю, - это метод оплаты счетов-фактур на продажу и / или покупку, уже введенных в систему бухгалтерского учета.
Я просто не знал, с чего начать, потому что было очень много разных способов оплаты. Счет-фактура может составлять 100 долларов, но клиент перевел только 99 долларов. Возможно, вы отправили счета-фактуры клиенту, но вы также совершили покупку у этого клиента. Итак, вы продали его за 300 долларов, но купили за 100 долларов. Вы можете ожидать, что ваш клиент заплатит вам 200 долларов для погашения баланса. А что, если вы продали за 500 долларов, а покупатель заплатит вам всего 250 долларов?
Итак, у меня была очень сложная проблема, которую нужно было решить, с множеством возможностей, что один сценарий будет работать идеально, но будет неправильным для другого типа комбинации счета / платежа.
Здесь на помощь пришло модульное тестирование.
Я начал писать (внутри тестового кода) метод создания списка счетов-фактур, как для продаж, так и для покупок. Затем я написал второй способ создания фактического платежа. Обычно пользователь вводит эту информацию через пользовательский интерфейс.
Затем я создал первый TestMethod, тестируя очень простую оплату одного счета без каких-либо скидок при оплате. Все действия в системе будут происходить, когда банковский платеж будет сохранен в базе данных. Как видите, я создал счет, создал платеж (банковскую транзакцию) и сохранил транзакцию на диск. В своих утверждениях я указываю правильные числа, которые должны отображаться в банковской транзакции и в связанном счете-фактуре. Я проверяю количество платежей, суммы платежей, сумму скидки и остаток счета после транзакции.
После запуска теста я заходил в базу данных и дважды проверял, есть ли там то, что я ожидал.
После Написал тест, начал кодировать метод оплаты (часть класса 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);
}
Нашли ошибку в вашем модульном тесте! Вы повторяете эту строку вместо того, чтобы включать 2 в одну из них: Assert.AreEqual(0, bankHeader.BankCashDetails[0].Payments[3].InvoiceHeader.Balance);
Вы говорите: «После запуска теста я обращался к базе данных и дважды проверял, было ли там то, что я ожидал». Это хороший пример интеграционного теста между компонентами вашей системы, а не изолированного модульного теста отдельного фрагмента кода.
Вы также нарушили правило более одного утверждения на тест.
Лучшее эмпирическое правило, которое я видел, - это проверить все, что вы не можете сказать с первого взгляда, наверняка будет работать правильно. Что-нибудь еще, и вы закончите тестирование языка / среды.
Этот вопрос, кажется, заключается в том, где провести черту, какие методы проверяются, а какие нет.
Установщики и получатели для присвоения значений были созданы с учетом согласованности и будущего роста, а также с учетом того, что через некоторое время установщики / получатели могут превратиться в более сложные операции. Было бы разумно внедрить модульные тесты этих методов, в том числе для обеспечения согласованности и будущего роста.
Надежность кода, особенно когда в него вносятся изменения для добавления дополнительных функций, является основной целью. Я не знаю, чтобы кого-нибудь когда-либо увольняли за включение сеттеров / получателей в методологию тестирования, но я уверен, что есть люди, которые хотели бы, чтобы они тестировали методы, которые в последний раз знали или могли вспомнить, были простыми обертками set / get, но это не было дольше дело.
Может быть, другой член команды расширил методы set / get, включив в них логику, которая теперь нуждается в тестировании, но не создавала тесты. Но теперь ваш код вызывает эти методы, и вы не знаете, что они изменились и нуждаются в глубоком тестировании, а тестирование, которое вы проводите при разработке и контроле качества, не вызывает дефект, но реальные бизнес-данные в первый день выпуска вызывают. вызвать это.
Теперь двое товарищей по команде будут обсуждать, кто упал и не прошел модульные тесты, когда набор / трансформируется, чтобы включить логику, которая может дать сбой, но не охвачена модульным тестом. Товарищу по команде, который изначально написал набор / получение, будет легче выйти из этой чистой, если тесты были реализованы с первого дня на простом наборе / получении.
Я считаю, что несколько минут «потраченного впустую» времени, покрывающего ВСЕ методы модульными тестами, даже тривиальными, могут сэкономить дни головной боли в будущем и потерю денег / репутации бизнеса и потерю работы.
И тот факт, что вы обернули тривиальные методы модульными тестами, может быть замечен этим младшим товарищем по команде, когда они изменят тривиальные методы на нетривиальные и предложат им обновить тест, и теперь никто не в беде, потому что дефект был устранен. от достижения производства.
То, как мы кодируем, и дисциплина, которую мы видим из нашего кода, могут помочь другим.
Этот пост поможет сузить более широкий вопрос: earnestengineer.blogspot.com/2018/03/… Вы можете воспользоваться этими рекомендациями, чтобы сфокусироваться на своем вопросе.