Есть юнит и интеграционные тесты. Модульное тестирование - это тестирование отдельных компонентов / классов / методов / функций и взаимодействия между ними, но только с одним реальным объектом (тестируемая система-SUT) и удвоение теста. Тестовые двойники можно разделить на пни и макеты. Заглушки предоставляют подготовленные тестовые данные в SUT. Таким образом, вы изолируете SUT от окружающей среды. Таким образом, вам не нужно обращаться к базам данных, веб-службам или службам wcf и т. Д., И у вас всегда одни и те же входные данные. Насмешки используются для проверки того, что SUT работает должным образом. SUT вызывает методы для фиктивного объекта, даже не зная, что это не настоящий объект. Затем Вы проверяете, что SUT работает, утверждая на фиктивном объекте. Вы можете написать заглушки и макеты вручную или использовать одну из многих фреймворков. Один из которых http://code.google.com/p/moq/
Если вы хотите протестировать взаимодействие с базой данных, это интеграционное тестирование и, как правило, намного сложнее. Для тестирования интеграции необходимо настроить внешние ресурсы в хорошо известном состоянии.
Давайте возьмем ваши слои:
Вы не сможете его протестировать. Страница тесно связана со средой выполнения ASP.NET. Вы должны стараться не иметь много кода в коде позади. Просто вызовите некоторые объекты из вашего кода и протестируйте эти объекты. Вы можете посмотреть на шаблоны дизайна MVC. Если вам необходимо проверить свою страницу, вам нужно посмотреть http://watin.org/. Он автоматизирует ваш интернет-браузер, нажимает кнопки на странице и проверяет, что на странице отображаются ожидаемые результаты.
Это интеграционное тестирование. Вы помещаете данные в базу данных, затем читаете их обратно и сравниваете результаты. После теста или до теста Вам необходимо привести тестовую базу данных в известное состояние, чтобы тесты можно было повторять. Мой совет - настроить базу данных до запуска теста, а не после теста. Таким образом, вы сможете проверить, что находится в базе данных после сбоя теста.
Я действительно не знаю, чем это отличается от этого в пункте №. 2.
И это модульное тестирование. Создайте объект в тесте, вызовите его методы и проверьте результаты.
Как проверить методы, которые устанавливают соединения с базой данных, описано в пункте 2.
Как не тратить время? Это придет с опытом. У меня нет общих советов, кроме как не тестировать свойства, в которых нет никакой логики.
Большую информацию о модульном тестировании смотрите здесь:
http://artofunittesting.com/
http://www.amazon.com/Test-Driven-Development-Kent-Beck/dp/0321146530
http://www.amazon.com/Growing-Object-Oriented-Software-Guided-Tests/dp/0321503627/ref=sr_1_2?ie=UTF8&s=books&qid=1306787051&sr=1-2
http://www.amazon.com/xUnit-Test-Patterns-Refactoring-Code/dp/0131495054/ref=sr_1_1?ie=UTF8&s=books&qid=1306787051&sr=1-1
Edit:
SUT, CUT - тестируемая система или класс. Это то, что вы тестируете.
Двойной тест - происходит от двойных трюков. Они снимают опасные сцены в фильмах, так что настоящим актерам это не нужно. Тоже самое. Двойные тесты заменяют реальные объекты в тестах, так что Вы можете изолировать SUT / CUT в тестах от окружающей среды.
Давайте посмотрим на этот класс
public class NotTestableParty
{
public bool ShouldStartPreparing()
{
if (DateTime.Now.Date == new DateTime(2011, 12, 31))
{
Console.WriteLine("Prepare for party!");
return true;
}
Console.WriteLine("Party is not today");
return false;
}
}
Как вы будете проверять, что этот класс делает то, что должен в канун Нового года? Вы должны сделать это в канун Нового года:)
Теперь посмотрите на модифицированный класс партии
Пример заглушки:
public class Party
{
private IClock clock;
public Party(IClock clock)
{
this.clock = clock;
}
public bool ShouldStartPreparing()
{
if (clock.IsNewYearsEve())
{
Console.WriteLine("Prepare for party!");
return true;
}
Console.WriteLine("Party is not today");
return false;
}
}
public interface IClock
{
bool IsNewYearsEve();
}
public class AlwaysNewYearsEveClock : IClock
{
public bool IsNewYearsEve()
{
return true;
}
}
Сейчас в тесте Вы можете передать поддельные часы классу Party
var party = new Party(new AlwaysNewYearsEveClock());
Assert.That(party.ShouldStartPreparing(), Is.True);
А теперь Вы знаете, работает ли класс вашей вечеринки в канун Нового года. AlwaysNewYearsEveClock является заглушкой.
Теперь посмотрите на этот класс:
public class UntestableCalculator
{
private Logger log = new Logger();
public decimal Divide(decimal x, decimal y)
{
if (y == 0m)
{
log.Log("Don't divide by 0");
}
return x / y;
}
}
public class Logger
{
public void Log(string message)
{
// .. do some logging
}
}
Как вы будете проверять, что ваш класс регистрирует сообщение. В зависимости от того, где вы регистрируете его, вы должны проверить файл или базу данных или другое место. Это был бы не модульный тест, а интеграционный тест. Для модульного тестирования Вы делаете это.
public class TestableCalculator
{
private ILogger log;
public TestableCalculator(ILogger logger)
{
log = logger;
}
public decimal Divide(decimal x, decimal y)
{
if (y == 0m)
{
log.Log("Don't divide by 0");
}
return x / y;
}
}
public interface ILogger
{
void Log(string message);
}
public class FakeLogger : ILogger
{
public string LastLoggedMessage;
public void Log(string message)
{
LastLoggedMessage = message;
}
}
А в тесте можно
var logger = new FakeLogger();
var calculator = new TestableCalculator(logger);
try
{
calculator.Divide(10, 0);
}
catch (DivideByZeroException ex)
{
Assert.That(logger.LastLoggedMessage, Is.EqualTo("Don't divide by 0"));
}
Здесь Вы утверждаете на поддельном логгере. Поддельный регистратор - фиктивный объект.