SlideShare a Scribd company logo
TESTING
~
TDD
Kalinichev.net	

!
TDD? ЧТО И ОТКУДА?
• Пошло из XP: test-first
TDD? ЧТО И ОТКУДА?
• Пошло из XP: test-first	

• Реже используешь отладчик
TDD? ЧТО И ОТКУДА?
• Пошло из XP: test-first	

• Реже используешь отладчик	

• Дизайн еще до реализации
TDD? ЧТО И ОТКУДА?
• Пошло из XP: test-first	

• Реже используешь отладчик	

• Дизайн еще до реализации	

• Код менее связанный
TDD? ЧТО И ОТКУДА?
• Пошло из XP: test-first	

• Реже используешь отладчик	

• Дизайн еще до реализации	

• Код менее связанный	

• Нет сложной инициализации
TDD? ЧТО И ОТКУДА?
• Пошло из XP: test-first	

• Реже используешь отладчик	

• Дизайн еще до реализации	

• Код менее связанный	

• Нет сложной инициализации	

• Интерфейсы четкие и небольшие
TDD? ЧТО И ОТКУДА?
• Пошло из XP: test-first	

• Реже используешь отладчик	

• Дизайн еще до реализации	

• Код менее связанный	

• Нет сложной инициализации	

• Интерфейсы четкие и небольшие	

• Способствует модульному мышлению	

!
TDD? ЧТО И ОТКУДА?
• Нужно привыкнуть
TDD? ЧТО И ОТКУДА?
• Нужно привыкнуть	

• На старте может потребовать больше времени
TDD? ЧТО И ОТКУДА?
• Нужно привыкнуть	

• На старте может потребовать больше времени	

• Может возникнуть ложное чувство безопасности
TDD? ЧТО И ОТКУДА?
• Нужно привыкнуть	

• На старте может потребовать больше времени	

• Может возникнуть ложное чувство безопасности	

• Плохо написанный тест - источник накладных расходов!
ПЛАН
• Что не так?	

• Как хочется?	

• Примеры	

• Примеры	

• Примеры	

• Практика
ЧТО ВЫ МОЖЕТЕ СКАЗАТЬ
О ТЕСТАХ?
Я ненавижу свои тесты
Я ненавижу свои тесты	

... да и чужие
ПОЧЕМУ?
•Медленные
•Медленные	

•Хрупкие
•Медленные	

•Хрупкие	

•Что еще хуже - Random’но хрупкие
•Медленные	

•Хрупкие	

•Что еще хуже - Random’но хрупкие	

•Дорогие по деньгам
•Медленные	

•Хрупкие	

•Что еще хуже - Random’но хрупкие	

•Дорогие по деньгам	

•Что еще хуже - по времени
•Медленные	

•Хрупкие	

•Что еще хуже - Random’но хрупкие	

•Дорогие по деньгам	

•Что еще хуже - по времени	

•Хрен поймешь - что тестируют?
•Медленные	

•Хрупкие	

•Что еще хуже - Random’но хрупкие	

•Дорогие по деньгам	

•Что еще хуже - по времени	

•Хрен поймешь - что тестируют?	

•Писать и разбираться в них - одна боль и
страдание
ТАК НЕ ДОЛЖНО БЫТЬ!
Давайте удалим такие тесты
Давайте удалим такие тесты
- Что все?
ЦЕЛЬ
UNIT ТЕСТЫ ДОЖНЫ БЫТЬ
UNIT ТЕСТЫ ДОЖНЫ БЫТЬ
•Полными
UNIT ТЕСТЫ ДОЖНЫ БЫТЬ
•Полными	

•Стабильными
UNIT ТЕСТЫ ДОЖНЫ БЫТЬ
•Полными	

•Стабильными	

•Быстрыми
UNIT ТЕСТЫ ДОЖНЫ БЫТЬ
•Полными	

•Стабильными	

•Быстрыми	

•Короткими
КАК ДЕЛА В КОДЕ НАШИХ
ПРОЕКТОВ?
КАК ДЕЛА В КОДЕ НАШИХ
ПРОЕКТОВ?
Давайте подумаем про один
какой-нибудь объект...
ОБЪЕКТ
•Получает что-то от кого-то	

•Отправляет что-то кому-то	

•Внутри сам себе покоя не дает
ВСЕ ЭТО НЕКИЕ
СООБЩЕНИЯ
СООБЩЕНИЯ МОЖНО
РАЗБИТЬ НА ДВА ТИПА
Запросы: 	

что-то возвращают и ничего не меняют
Запросы: 	

что-то возвращают и ничего не меняют
Команды: 	

ничего не возвращают и что-то меняют
Запросы: 	

что-то возвращают и ничего не меняют
Команды: 	

ничего не возвращают и что-то меняют
Избавляйтесь от запросов, которые ведут
себя как команды
i
ЧТО И КАК ТЕСТИРОВАТЬ
Запросы Команды
Входящие
Самому себе
Исходящие
ВХОДЯЩИЕ СООБЩЕНИЯ
ВХОДЯЩИЕ ЗАПРОСЫ
private class Aggregator {!
private readonly int[] _args;!
public Aggregator(params int[] args) {!
_args = args;!
}!
public int Sum {!
get { return _args.Sum(); }!
}!
}!
!
ВХОДЯЩИЕ ЗАПРОСЫ
private class Aggregator {!
private readonly int[] _args;!
public Aggregator(params int[] args) {!
_args = args;!
}!
public int Sum {!
get { return _args.Sum(); }!
}!
}!
!
[TestFixture]!
public class AggregatorTest {!
[Test]!
public void Sum() {!
var a = new Aggregator(1, 2, 3);!
Assert.AreEqual(6, a.Sum);!
}!
}!
ВХОДЯЩИЕ ЗАПРОСЫ
Правило 1	

!
Тестируем входящие запросы по тому что они
возвращают
R
ВХОДЯЩИЕ ЗАПРОСЫ
!
private class MyAverage {!
public const int MAGIC_COEF = 2;!
private readonly int[] _args;!
public MyAverage(params int[] args) {!
_args = args;!
}!
public int Calc() {!
return new Aggregator(ModifyArgs).Sum / _args.Length;!
}!
private int[] ModifyArgs {!
get { return _args.Select(a => a * MAGIC_COEF).ToArray(); }!
}!
}!
!
ВХОДЯЩИЕ ЗАПРОСЫ
!
private class MyAverage {!
public const int MAGIC_COEF = 2;!
private readonly int[] _args;!
public MyAverage(params int[] args) {!
_args = args;!
}!
public int Calc() {!
return new Aggregator(ModifyArgs).Sum / _args.Length;!
}!
private int[] ModifyArgs {!
get { return _args.Select(a => a * MAGIC_COEF).ToArray(); }!
}!
}!
!
[TestFixture]!
public class MyAverageTest {!
[Test]!
public void Calc() {!
var avg = new MyAverage(10, 20);!
Assert.AreEqual(30, avg.Calc());!
// Но, там же еще всего так много: MAGIC_COEF, ModifyArgs.!
}!
}!
ВХОДЯЩИЕ ЗАПРОСЫ
Правило 2	

!
Тестируем интерфейсы, а не конкретную
реализацию
R
ВХОДЯЩИЕ КОМАНДЫ
!
private class MyAverage2 : MyAverage {!
private int _coef;!
!
public void SetCoef(int value) {!
_coef = value;!
}!
!
public int CurrentMagicCoef { get { return _coef + MAGIC_COEF; } }!
}!
!
ВХОДЯЩИЕ КОМАНДЫ
!
private class MyAverage2 : MyAverage {!
private int _coef;!
!
public void SetCoef(int value) {!
_coef = value;!
}!
!
public int CurrentMagicCoef { get { return _coef + MAGIC_COEF; } }!
}!
!
[TestFixture]!
public class MyAverage2Test {!
[Test]!
public void SetCoef() {!
var avg = new MyAverage2();!
avg.SetCoef(1);!
Assert.AreEqual(3, avg.CurrentMagicCoef);!
}!
}!
ВХОДЯЩИЕ КОМАНДЫ
Правило 3	

!
Тестируем входящие команды по ближайшему
публичному, побочному эффекту
R
ЧТО И КАК ТЕСТИРОВАТЬ
Запросы Команды
Входящие
Проверка
результата
Проверка публичного,
побочного эффекта
Самому себе
Исходящие
СООБЩЕНИЯ САМОМУ
СЕБЕ
ЗАПРОСЫ К СЕБЕ
!
private class MyAverage4 {!
public const int MAGIC_COEF = 2;!
private readonly int[] _args;!
public MyAverage4(params int[] args) {!
_args = args;!
}!
public int Calc() {!
return new Aggregator(ModifyArgs).Sum / _args.Length;!
}!
internal int[] ModifyArgs {!
get { return _args.Select(a => a * MAGIC_COEF).ToArray(); }!
}!
}!
!
!
ЗАПРОСЫ К СЕБЕ
!
private class MyAverage4 {!
public const int MAGIC_COEF = 2;!
private readonly int[] _args;!
public MyAverage4(params int[] args) {!
_args = args;!
}!
public int Calc() {!
return new Aggregator(ModifyArgs).Sum / _args.Length;!
}!
internal int[] ModifyArgs {!
get { return _args.Select(a => a * MAGIC_COEF).ToArray(); }!
}!
}!
!
!
ЗАПРОСЫ К СЕБЕ
!
private class MyAverage4 {!
public const int MAGIC_COEF = 2;!
private readonly int[] _args;!
public MyAverage4(params int[] args) {!
_args = args;!
}!
public int Calc() {!
return new Aggregator(ModifyArgs).Sum / _args.Length;!
}!
internal int[] ModifyArgs {!
get { return _args.Select(a => a * MAGIC_COEF).ToArray(); }!
}!
}!
!
[TestFixture]!
public class MyAverage4Test {!
[Test]!
public void ModifyArgs() {!
var avg = new MyAverage4(10);!
Assert.AreEqual(20, avg.ModifyArgs);!
}!
}!
ЗАПРОСЫ К СЕБЕ
!
private class MyAverage4 {!
public const int MAGIC_COEF = 2;!
private readonly int[] _args;!
public MyAverage4(params int[] args) {!
_args = args;!
}!
public int Calc() {!
return new Aggregator(ModifyArgs).Sum / _args.Length;!
}!
internal int[] ModifyArgs {!
get { return _args.Select(a => a * MAGIC_COEF).ToArray(); }!
}!
}!
!
[TestFixture]!
public class MyAverage4Test {!
[Test]!
public void ModifyArgs() {!
var avg = new MyAverage4(10);!
Assert.AreEqual(20, avg.ModifyArgs);!
}!
}!
ТАК ДЕЛАТЬ НЕ НАДО
КОМАНДЫ К СЕБЕ
!
private class MyAverage5 {!
private readonly int[] _args;!
internal Aggregator Aggregator;!
public MyAverage5(params int[] args) {!
_args = args;!
}!
public int Calc() {!
InitAggregator()!
return Aggregator.Sum / _args.Length;!
}!
private void InitAggregator() {!
Aggregator = new Aggregator(_args);!
}!
}!
КОМАНДЫ К СЕБЕ
!
private class MyAverage5 {!
private readonly int[] _args;!
internal Aggregator Aggregator;!
public MyAverage5(params int[] args) {!
_args = args;!
}!
public int Calc() {!
InitAggregator()!
return Aggregator.Sum / _args.Length;!
}!
private void InitAggregator() {!
Aggregator = new Aggregator(_args);!
}!
}!
!
[TestFixture]!
public class MyAverage5Test {!
[Test]!
public void Calc() {!
var avg = new MyAverage5(10, 20);!
Assert.AreEqual(15, avg.Calc());!
Assert.IsNotNull(avg.Aggregator);!
}!
}!
КОМАНДЫ К СЕБЕ
!
private class MyAverage5 {!
private readonly int[] _args;!
internal Aggregator Aggregator;!
public MyAverage5(params int[] args) {!
_args = args;!
}!
public int Calc() {!
InitAggregator()!
return Aggregator.Sum / _args.Length;!
}!
private void InitAggregator() {!
Aggregator = new Aggregator(_args);!
}!
}!
!
[TestFixture]!
public class MyAverage5Test {!
[Test]!
public void Calc() {!
var avg = new MyAverage5(10, 20);!
Assert.AreEqual(15, avg.Calc());!
Assert.IsNotNull(avg.Aggregator);!
}!
}!
Этому тут не место
КОМАНДЫ К СЕБЕ
!
private class MyAverage5 {!
private readonly int[] _args;!
internal Aggregator Aggregator;!
public MyAverage5(params int[] args) {!
_args = args;!
}!
public int Calc() {!
InitAggregator()!
return Aggregator.Sum / _args.Length;!
}!
private void InitAggregator() {!
Aggregator = new Aggregator(_args);!
}!
}!
!
[TestFixture]!
public class MyAverage5Test {!
[Test]!
public void Calc() {!
var avg = new MyAverage5(10, 20);!
Assert.AreEqual(15, avg.Calc());!
Assert.IsNotNull(avg.Aggregator);!
}!
}!
ТАК ДЕЛАТЬ НЕ НАДО
СООБЩЕНИЯ САМОМУ
СЕБЕ
Правило 4	

!
Не тестируйте внутренние методы	

- не проверяйте их результат	

- не ожидайте их вызова
R
ЧТО И КАК ТЕСТИРОВАТЬ
Запросы Команды
Входящие
Проверка
результата
Проверка публичного,
побочного эффекта
Самому себе Игнорируем Игнорируем
Исходящие
ИСХОДЯЩИЕ СООБЩЕНИЯ
ИСХОДЯЩИЕ ЗАПРОСЫ
!
public interface IMagicCoef {!
int Value { get; }!
}!
class MagicCoef : IMagicCoef {!
public int Value { !
get { return /* Find Magic Value... */ default(int); } }!
}!
!
private class MyAverage6 {!
private readonly IMagicCoef _magic;!
private readonly int[] _args;!
public MyAverage6(IMagicCoef magic = null, params int[] args) {!
_magic = magic ?? new MagicCoef();!
_args = args;!
}!
public int Calc() {!
return new Aggregator(ModifyArgs).Sum / _args.Length;!
}!
private int[] ModifyArgs {!
get { return _args.Select(a => a * _magic.Value).ToArray(); }!
}!
}!
ИСХОДЯЩИЕ ЗАПРОСЫ
!
public interface IMagicCoef {!
int Value { get; }!
}!
class MagicCoef : IMagicCoef {!
public int Value { !
get { return /* Find Magic Value... */ default(int); } }!
}!
!
private class MyAverage6 {!
private readonly IMagicCoef _magic;!
private readonly int[] _args;!
public MyAverage6(IMagicCoef magic = null, params int[] args) {!
_magic = magic ?? new MagicCoef();!
_args = args;!
}!
public int Calc() {!
return new Aggregator(ModifyArgs).Sum / _args.Length;!
}!
private int[] ModifyArgs {!
get { return _args.Select(a => a * _magic.Value).ToArray(); }!
}!
}!
ИСХОДЯЩИЕ ЗАПРОСЫ
!
class MagicCoef : IMagicCoef {!
public int Value { !
get { return /* Find Magic Value... */ default(int); } }!
}!
!
private class MyAverage6 {!
...!
public int Calc() {!
return new Aggregator(ModifyArgs).Sum / _args.Length;!
}!
private int[] ModifyArgs {!
get { return _args.Select(a => a * _magic.Value).ToArray(); }!
}!
}!
!
[TestFixture]!
public class MyAverage6Test {!
[Test]!
public void CallMagic() {!
var mock = new Mock<IMagicCoef>();!
new MyAverage6(mock.Object, 1, 2).Calc();!
mock.Verify(m => m.Value, Times.Exactly(2));!
}!
}!
!
ИСХОДЯЩИЕ ЗАПРОСЫ
!
class MagicCoef : IMagicCoef {!
public int Value { !
get { return /* Find Magic Value... */ default(int); } }!
}!
!
private class MyAverage6 {!
...!
public int Calc() {!
return new Aggregator(ModifyArgs).Sum / _args.Length;!
}!
private int[] ModifyArgs {!
get { return _args.Select(a => a * _magic.Value).ToArray(); }!
}!
}!
!
[TestFixture]!
public class MyAverage6Test {!
[Test]!
public void CallMagic() {!
var mock = new Mock<IMagicCoef>();!
new MyAverage6(mock.Object, 1, 2).Calc();!
mock.Verify(m => m.Value, Times.Exactly(2));!
}!
}!
!
ТАК ДЕЛАТЬ НЕ НАДО
ИСХОДЯЩИЕ ЗАПРОСЫ
Правило 5	

!
Не тестируйте исходящие запросы	

- не проверяйте их результат	

- не ожидайте их вызова
R
ИСХОДЯЩИЕ ЗАПРОСЫ
Правило 5	

!
Не тестируйте исходящие запросы	

- не проверяйте их результат	

- не ожидайте их вызова
R
Проверка исходящих запросов добавляет
стоимости, но не приносит пользы
i
ИСХОДЯЩИЕ КОМАНДЫ!
!
private class Aggregator7 {!
private readonly ILogger _logger;!
private readonly int[] _args;!
public Aggregator7(ILogger logger = null, params int[] args) {!
_logger = logger ?? new LoggerByDb();!
_args = args;!
}!
!
public int Sum {!
get {!
var sum = _args.Sum();!
_logger.LogSum(sum);!
return sum;!
}!
}!
}!
!
public interface ILogger {!
void LogSum(int sum);!
}!
!
private class LoggerByDb : ILogger {!
public void LogSum(int sum) {!
// Log sum in data base...!
}!
}!
ИСХОДЯЩИЕ КОМАНДЫ!
!
private class Aggregator7 {!
private readonly ILogger _logger;!
private readonly int[] _args;!
public Aggregator7(ILogger logger = null, params int[] args) {!
_logger = logger ?? new LoggerByDb();!
_args = args;!
}!
!
public int Sum {!
get {!
var sum = _args.Sum();!
_logger.LogSum(sum);!
return sum;!
}!
}!
}!
!
public interface ILogger {!
void LogSum(int sum);!
}!
!
private class LoggerByDb : ILogger {!
public void LogSum(int sum) {!
// Log sum in data base...!
}!
}!
ИСХОДЯЩИЕ КОМАНДЫ!
[TestFixture]!
public class Aggregator7Test {!
[Test]!
public void LogTest() {!
var sum = new Aggregator7(new LoggerByDb(), 1, 2, 3).Sum;!
var logSum = GetLogsFromDb();!
Assert.AreEqual(sum, logSum);!
}!
!
private int GetLogsFromDb() {!
// select sum from logtable limit 1;!
return default (int);!
}!
}!
ИСХОДЯЩИЕ КОМАНДЫ!
[TestFixture]!
public class Aggregator7Test {!
[Test]!
public void LogTest() {!
var sum = new Aggregator7(new LoggerByDb(), 1, 2, 3).Sum;!
var logSum = GetLogsFromDb();!
Assert.AreEqual(sum, logSum);!
}!
!
private int GetLogsFromDb() {!
// select sum from logtable limit 1;!
return default (int);!
}!
}!
Это зависимость от «далеких» эффектов
и конкретной реализации.	

Замедляет тесты.
i
ИСХОДЯЩИЕ КОМАНДЫ!
[TestFixture]!
public class Aggregator7Test {!
[Test]!
public void LogTest() {!
var sum = new Aggregator7(new LoggerByDb(), 1, 2, 3).Sum;!
var logSum = GetLogsFromDb();!
Assert.AreEqual(sum, logSum);!
}!
!
private int GetLogsFromDb() {!
// select sum from logtable limit 1;!
return default (int);!
}!
}!
Это зависимость от «далеких» эффектов
и конкретной реализации.	

Замедляет тесты.	

Главное - не имеет отношение к
ответственности класса.
i
ИСХОДЯЩИЕ КОМАНДЫ!
[TestFixture]!
public class Aggregator7Test {!
[Test]!
public void LogTest() {!
var sum = new Aggregator7(new LoggerByDb(), 1, 2, 3).Sum;!
var logSum = GetLogsFromDb();!
Assert.AreEqual(sum, logSum);!
}!
!
private int GetLogsFromDb() {!
// select sum from logtable limit 1;!
return default (int);!
}!
}!
Это зависимость от «далеких» эффектов
и конкретной реализации.	

Замедляет тесты.	

Главное - не имеет отношение к
ответственности класса.
i
ТАК ДЕЛАТЬ НЕ НАДО
ИСХОДЯЩИЕ КОМАНДЫ!
[TestFixture]!
public class Aggregator7Test {!
// Anti pattern!
[Test]!
public void BadLogTest() {!
var sum = new Aggregator7(new LoggerByDb(), 1, 2, 3).Sum;!
var logSum = GetLogsFromDb();!
Assert.AreEqual(sum, logSum);!
}!
!
private int GetLogsFromDb() {!
// select sum from logtable limit 1;!
return default (int);!
}!
!
// Good!
[Test]!
public void GoodLogTest() {!
var m = new Mock<ILogger>();!
var res = new Aggregator7(m.Object, 1, 2, 3).Sum;!
m.Verify(e => e.LogSum(6), Times.Once());!
}!
}!
ИСХОДЯЩИЕ КОМАНДЫ!
[TestFixture]!
public class Aggregator7Test {!
// Anti pattern!
[Test]!
public void BadLogTest() {!
var sum = new Aggregator7(new LoggerByDb(), 1, 2, 3).Sum;!
var logSum = GetLogsFromDb();!
Assert.AreEqual(sum, logSum);!
}!
!
private int GetLogsFromDb() {!
// select sum from logtable limit 1;!
return default (int);!
}!
!
// Good!
[Test]!
public void GoodLogTest() {!
var m = new Mock<ILogger>();!
var res = new Aggregator7(m.Object, 1, 2, 3).Sum;!
m.Verify(e => e.LogSum(6), Times.Once());!
}!
}!
Ответственность класса - отправить командуi
ИСХОДЯЩИЕ КОМАНДЫ
Правило 6	

!
Проверяйте отправку исходящих команд с
определенными параметрами, но не более того
R
ИСХОДЯЩИЕ КОМАНДЫ
Правило 6	

!
Проверяйте отправку исходящих команд с
определенными параметрами, но не более того
R
НО...
ИСХОДЯЩИЕ КОМАНДЫ
Что будет если интерфейс ILogger захочется
изменить?
ИСХОДЯЩИЕ КОМАНДЫ
Что будет если интерфейс ILogger захочется
изменить?
БОЛЬ И СТРАДАНИЕ
ИСХОДЯЩИЕ КОМАНДЫ
Что будет если интерфейс ILogger захочется
изменить?
БОЛЬ И СТРАДАНИЕ
Создавайте «тоникие» интерфейсы.
Соблюдайте контракты
i
ЧТО И КАК ТЕСТИРОВАТЬ
Запросы Команды
Входящие
Проверка
результата
Проверка публичного,
побочного эффекта
Самому себе Игнорируем Игнорируем
Исходящие Игнорируем Ожидание вызова
ИТОГО
БУДЬТЕ МИНИМАЛИСТОМ
БУДЬТЕ МИНИМАЛИСТОМ
в хорошем смысле
ТЕСТИРУЙТЕ ВСЕ
ТЕСТИРУЙТЕ ВСЕ
Только ОДИН раз
НАСТАИВАЙТЕ НА
ПРОСТОТЕ
У каждого есть возможность сказать:
У каждого есть возможность сказать:
«Я обожаю свои тесты»
ВОПРОСЫ
TDD
Внимание!
Очень сложно, но крайне важно
... это всё
ВОПРОСЫ
ССЫЛКИ
• http://en.wikipedia.org/wiki/Test-driven_development	

• https://speakerdeck.com/skmetz/magic-tricks-of-testing-
railsconf
Практическая часть
ВОПРОСЫ

More Related Content

What's hot

Automation Functional Testing in Agile Projects
Automation Functional Testing in Agile ProjectsAutomation Functional Testing in Agile Projects
Automation Functional Testing in Agile ProjectsAndrey Rebrov
 
Объекты в ECMAScript | Odessa Frontend Meetup #16
Объекты в ECMAScript | Odessa Frontend Meetup #16Объекты в ECMAScript | Odessa Frontend Meetup #16
Объекты в ECMAScript | Odessa Frontend Meetup #16OdessaFrontend
 
Legacy: как победить в гонке (Joker)
Legacy: как победить в гонке (Joker)Legacy: как победить в гонке (Joker)
Legacy: как победить в гонке (Joker)Victor_Cr
 
Использование Fiddler и Charles при тестировании фронтенда проекта pulse.mail...
Использование Fiddler и Charles при тестировании фронтенда проекта pulse.mail...Использование Fiddler и Charles при тестировании фронтенда проекта pulse.mail...
Использование Fiddler и Charles при тестировании фронтенда проекта pulse.mail...Mail.ru Group
 
JPoint 2016 - Etudes of DIY Java profiler
JPoint 2016 - Etudes of DIY Java profilerJPoint 2016 - Etudes of DIY Java profiler
JPoint 2016 - Etudes of DIY Java profilerAnton Arhipov
 
Типичные ошибки начинающих писать тесты на WebDriver
Типичные ошибки начинающих писать тесты на WebDriverТипичные ошибки начинающих писать тесты на WebDriver
Типичные ошибки начинающих писать тесты на WebDriverIgor Khrol
 
Поговорим о JavaScript, основы и современные тенденции развития языка
Поговорим о JavaScript, основы и современные тенденции развития языкаПоговорим о JavaScript, основы и современные тенденции развития языка
Поговорим о JavaScript, основы и современные тенденции развития языкаAlexander Kucherenko
 
Учим автотесты человеческому языку с помощью Allure и PyTest
Учим автотесты человеческому языку с помощью Allure и PyTestУчим автотесты человеческому языку с помощью Allure и PyTest
Учим автотесты человеческому языку с помощью Allure и PyTestRina Uzhevko
 
Groovy jug-moscow-part 1
Groovy jug-moscow-part 1Groovy jug-moscow-part 1
Groovy jug-moscow-part 1Evgeny Borisov
 
C++ CoreHard Autumn 2018. Заглядываем под капот «Поясов по C++» - Илья Шишков
C++ CoreHard Autumn 2018. Заглядываем под капот «Поясов по C++» - Илья ШишковC++ CoreHard Autumn 2018. Заглядываем под капот «Поясов по C++» - Илья Шишков
C++ CoreHard Autumn 2018. Заглядываем под капот «Поясов по C++» - Илья Шишковcorehard_by
 
Очень вкусный фрукт Guava
Очень вкусный фрукт GuavaОчень вкусный фрукт Guava
Очень вкусный фрукт GuavaEgor Chernyshev
 
JVM: краткий курс общей анатомии, JPoint 2016 Conference Edition
JVM: краткий курс общей анатомии, JPoint 2016 Conference EditionJVM: краткий курс общей анатомии, JPoint 2016 Conference Edition
JVM: краткий курс общей анатомии, JPoint 2016 Conference EditionNikita Lipsky
 
От Зефира в коробке к Structure Zephyr или как тест-менеджеру перекроить внут...
От Зефира в коробке к Structure Zephyr или как тест-менеджеру перекроить внут...От Зефира в коробке к Structure Zephyr или как тест-менеджеру перекроить внут...
От Зефира в коробке к Structure Zephyr или как тест-менеджеру перекроить внут...SQALab
 
Верификация Java байткода: когда, как, а может отключить?
Верификация Java байткода: когда, как, а может отключить?Верификация Java байткода: когда, как, а может отключить?
Верификация Java байткода: когда, как, а может отключить?Nikita Lipsky
 
Автоматизация функционального тестирования REST API
Автоматизация функционального тестирования REST APIАвтоматизация функционального тестирования REST API
Автоматизация функционального тестирования REST APIPavel Asanov
 

What's hot (20)

Automation Functional Testing in Agile Projects
Automation Functional Testing in Agile ProjectsAutomation Functional Testing in Agile Projects
Automation Functional Testing in Agile Projects
 
Объекты в ECMAScript | Odessa Frontend Meetup #16
Объекты в ECMAScript | Odessa Frontend Meetup #16Объекты в ECMAScript | Odessa Frontend Meetup #16
Объекты в ECMAScript | Odessa Frontend Meetup #16
 
Legacy: как победить в гонке (Joker)
Legacy: как победить в гонке (Joker)Legacy: как победить в гонке (Joker)
Legacy: как победить в гонке (Joker)
 
Использование Fiddler и Charles при тестировании фронтенда проекта pulse.mail...
Использование Fiddler и Charles при тестировании фронтенда проекта pulse.mail...Использование Fiddler и Charles при тестировании фронтенда проекта pulse.mail...
Использование Fiddler и Charles при тестировании фронтенда проекта pulse.mail...
 
JPoint 2016 - Etudes of DIY Java profiler
JPoint 2016 - Etudes of DIY Java profilerJPoint 2016 - Etudes of DIY Java profiler
JPoint 2016 - Etudes of DIY Java profiler
 
Curse of spring boot test [VRN]
Curse of spring boot test [VRN]Curse of spring boot test [VRN]
Curse of spring boot test [VRN]
 
Типичные ошибки начинающих писать тесты на WebDriver
Типичные ошибки начинающих писать тесты на WebDriverТипичные ошибки начинающих писать тесты на WebDriver
Типичные ошибки начинающих писать тесты на WebDriver
 
Поговорим о JavaScript, основы и современные тенденции развития языка
Поговорим о JavaScript, основы и современные тенденции развития языкаПоговорим о JavaScript, основы и современные тенденции развития языка
Поговорим о JavaScript, основы и современные тенденции развития языка
 
Учим автотесты человеческому языку с помощью Allure и PyTest
Учим автотесты человеческому языку с помощью Allure и PyTestУчим автотесты человеческому языку с помощью Allure и PyTest
Учим автотесты человеческому языку с помощью Allure и PyTest
 
Spring data jee conf
Spring data jee confSpring data jee conf
Spring data jee conf
 
Groovy jug-moscow-part 1
Groovy jug-moscow-part 1Groovy jug-moscow-part 1
Groovy jug-moscow-part 1
 
C++ CoreHard Autumn 2018. Заглядываем под капот «Поясов по C++» - Илья Шишков
C++ CoreHard Autumn 2018. Заглядываем под капот «Поясов по C++» - Илья ШишковC++ CoreHard Autumn 2018. Заглядываем под капот «Поясов по C++» - Илья Шишков
C++ CoreHard Autumn 2018. Заглядываем под капот «Поясов по C++» - Илья Шишков
 
Java 8 puzzlers
Java 8 puzzlersJava 8 puzzlers
Java 8 puzzlers
 
Selenium vs AJAX
Selenium vs AJAXSelenium vs AJAX
Selenium vs AJAX
 
Очень вкусный фрукт Guava
Очень вкусный фрукт GuavaОчень вкусный фрукт Guava
Очень вкусный фрукт Guava
 
JVM: краткий курс общей анатомии, JPoint 2016 Conference Edition
JVM: краткий курс общей анатомии, JPoint 2016 Conference EditionJVM: краткий курс общей анатомии, JPoint 2016 Conference Edition
JVM: краткий курс общей анатомии, JPoint 2016 Conference Edition
 
От Зефира в коробке к Structure Zephyr или как тест-менеджеру перекроить внут...
От Зефира в коробке к Structure Zephyr или как тест-менеджеру перекроить внут...От Зефира в коробке к Structure Zephyr или как тест-менеджеру перекроить внут...
От Зефира в коробке к Structure Zephyr или как тест-менеджеру перекроить внут...
 
Spring puzzlers
Spring puzzlersSpring puzzlers
Spring puzzlers
 
Верификация Java байткода: когда, как, а может отключить?
Верификация Java байткода: когда, как, а может отключить?Верификация Java байткода: когда, как, а может отключить?
Верификация Java байткода: когда, как, а может отключить?
 
Автоматизация функционального тестирования REST API
Автоматизация функционального тестирования REST APIАвтоматизация функционального тестирования REST API
Автоматизация функционального тестирования REST API
 

Viewers also liked

Presentacion de que es power point
Presentacion de que es power pointPresentacion de que es power point
Presentacion de que es power pointobfloresc
 
Kinnaur & Spiti – The Offbeat Himalayas
Kinnaur & Spiti – The Offbeat HimalayasKinnaur & Spiti – The Offbeat Himalayas
Kinnaur & Spiti – The Offbeat Himalayasgarimajain834
 
How to learn English
How to learn EnglishHow to learn English
How to learn EnglishPhong Dang
 
dave_peters_CV1_2015 (2)
dave_peters_CV1_2015 (2)dave_peters_CV1_2015 (2)
dave_peters_CV1_2015 (2)David Peters
 
AIG Second Quarter 2008 Financial Supplement
AIG Second Quarter 2008 Financial SupplementAIG Second Quarter 2008 Financial Supplement
AIG Second Quarter 2008 Financial Supplementfinance2
 
cardinal health Q1 2009 Earnings Release
cardinal health Q1 2009 Earnings Releasecardinal health Q1 2009 Earnings Release
cardinal health Q1 2009 Earnings Releasefinance2
 
AIG Annual Reports and Proxy Statements 2005 Form 10-K
AIG Annual Reports and Proxy Statements 2005 Form 10-KAIG Annual Reports and Proxy Statements 2005 Form 10-K
AIG Annual Reports and Proxy Statements 2005 Form 10-Kfinance2
 
valero energy Quarterly and Other SEC Reports 2007 3rd
valero energy Quarterly and Other SEC Reports  2007 3rdvalero energy Quarterly and Other SEC Reports  2007 3rd
valero energy Quarterly and Other SEC Reports 2007 3rdfinance2
 

Viewers also liked (15)

Presentacion de que es power point
Presentacion de que es power pointPresentacion de que es power point
Presentacion de que es power point
 
Mario rivas auditoria
Mario rivas auditoriaMario rivas auditoria
Mario rivas auditoria
 
ECG EN ENFERMERIA
ECG EN ENFERMERIAECG EN ENFERMERIA
ECG EN ENFERMERIA
 
RTF343_FALL2007_SYLLABUS_05
RTF343_FALL2007_SYLLABUS_05RTF343_FALL2007_SYLLABUS_05
RTF343_FALL2007_SYLLABUS_05
 
Enas AbuLouzCV
Enas AbuLouzCVEnas AbuLouzCV
Enas AbuLouzCV
 
Kinnaur & Spiti – The Offbeat Himalayas
Kinnaur & Spiti – The Offbeat HimalayasKinnaur & Spiti – The Offbeat Himalayas
Kinnaur & Spiti – The Offbeat Himalayas
 
Gestion del talento (esquema)
Gestion del talento (esquema)Gestion del talento (esquema)
Gestion del talento (esquema)
 
How to learn English
How to learn EnglishHow to learn English
How to learn English
 
dave_peters_CV1_2015 (2)
dave_peters_CV1_2015 (2)dave_peters_CV1_2015 (2)
dave_peters_CV1_2015 (2)
 
St05689.en17
St05689.en17St05689.en17
St05689.en17
 
Teoria de comportamiento humano
Teoria de comportamiento humanoTeoria de comportamiento humano
Teoria de comportamiento humano
 
AIG Second Quarter 2008 Financial Supplement
AIG Second Quarter 2008 Financial SupplementAIG Second Quarter 2008 Financial Supplement
AIG Second Quarter 2008 Financial Supplement
 
cardinal health Q1 2009 Earnings Release
cardinal health Q1 2009 Earnings Releasecardinal health Q1 2009 Earnings Release
cardinal health Q1 2009 Earnings Release
 
AIG Annual Reports and Proxy Statements 2005 Form 10-K
AIG Annual Reports and Proxy Statements 2005 Form 10-KAIG Annual Reports and Proxy Statements 2005 Form 10-K
AIG Annual Reports and Proxy Statements 2005 Form 10-K
 
valero energy Quarterly and Other SEC Reports 2007 3rd
valero energy Quarterly and Other SEC Reports  2007 3rdvalero energy Quarterly and Other SEC Reports  2007 3rd
valero energy Quarterly and Other SEC Reports 2007 3rd
 

Similar to Testing & TDD

Лекция 11. Тестирование.
Лекция 11. Тестирование.Лекция 11. Тестирование.
Лекция 11. Тестирование.Roman Brovko
 
TDD или как я стараюсь писать код
TDD или как я стараюсь писать кодTDD или как я стараюсь писать код
TDD или как я стараюсь писать кодMoscowDjango
 
Юлия Ковалёва. Fscheck — альтернативный путь для unit тестов
Юлия Ковалёва. Fscheck — альтернативный путь для unit тестовЮлия Ковалёва. Fscheck — альтернативный путь для unit тестов
Юлия Ковалёва. Fscheck — альтернативный путь для unit тестовMskDotNet Community
 
AgileCamp’11 Новосибирск - Test Driven Development (TDD)
AgileCamp’11 Новосибирск - Test Driven Development (TDD)AgileCamp’11 Новосибирск - Test Driven Development (TDD)
AgileCamp’11 Новосибирск - Test Driven Development (TDD)Anton Katkov
 
Как сделать ваш JavaScript быстрее
Как сделать ваш JavaScript быстрееКак сделать ваш JavaScript быстрее
Как сделать ваш JavaScript быстрееRoman Dvornov
 
TDD или как я стараюсь писать код
TDD или как я стараюсь писать кодTDD или как я стараюсь писать код
TDD или как я стараюсь писать кодVladimir Filonov
 
Как сделать ваш JavaScript быстрее / Роман Дворнов (Авито)
Как сделать ваш JavaScript быстрее / Роман Дворнов (Авито)Как сделать ваш JavaScript быстрее / Роман Дворнов (Авито)
Как сделать ваш JavaScript быстрее / Роман Дворнов (Авито)Ontico
 
"Outside In". Web application testing.
"Outside In". Web application testing."Outside In". Web application testing.
"Outside In". Web application testing.Mad Devs
 
XP Days Ukraine 2014 - Refactoring legacy code
XP Days Ukraine 2014 - Refactoring legacy codeXP Days Ukraine 2014 - Refactoring legacy code
XP Days Ukraine 2014 - Refactoring legacy codeDmytro Mindra
 
Jbreak 2016: Твой личный Spring Boot Starter
Jbreak 2016: Твой личный Spring Boot StarterJbreak 2016: Твой личный Spring Boot Starter
Jbreak 2016: Твой личный Spring Boot StarterAleksandr Tarasov
 
kranonit S11E01 Андрей Пономарёв: Тренинг по TDD в Java
kranonit S11E01 Андрей Пономарёв: Тренинг по TDD в Javakranonit S11E01 Андрей Пономарёв: Тренинг по TDD в Java
kranonit S11E01 Андрей Пономарёв: Тренинг по TDD в JavaKrivoy Rog IT Community
 
разработка бизнес приложений (8)
разработка бизнес приложений (8)разработка бизнес приложений (8)
разработка бизнес приложений (8)Alexander Gornik
 
Функциональное тестирование высоконагруженных проектов / Илья Пастушков (2ГИС)
Функциональное тестирование высоконагруженных проектов / Илья Пастушков (2ГИС)Функциональное тестирование высоконагруженных проектов / Илья Пастушков (2ГИС)
Функциональное тестирование высоконагруженных проектов / Илья Пастушков (2ГИС)Ontico
 
Готовим тестовое окружение, или сколько тестовых инстансов вам нужно / Алекса...
Готовим тестовое окружение, или сколько тестовых инстансов вам нужно / Алекса...Готовим тестовое окружение, или сколько тестовых инстансов вам нужно / Алекса...
Готовим тестовое окружение, или сколько тестовых инстансов вам нужно / Алекса...Ontico
 
Повышение качества тестов и автоматическая валидация REST API документации
Повышение качества тестов и автоматическая валидация REST API документацииПовышение качества тестов и автоматическая валидация REST API документации
Повышение качества тестов и автоматическая валидация REST API документацииCEE-SEC(R)
 

Similar to Testing & TDD (20)

Лекция 11. Тестирование.
Лекция 11. Тестирование.Лекция 11. Тестирование.
Лекция 11. Тестирование.
 
BDD
BDDBDD
BDD
 
TDD или как я стараюсь писать код
TDD или как я стараюсь писать кодTDD или как я стараюсь писать код
TDD или как я стараюсь писать код
 
Юлия Ковалёва. Fscheck — альтернативный путь для unit тестов
Юлия Ковалёва. Fscheck — альтернативный путь для unit тестовЮлия Ковалёва. Fscheck — альтернативный путь для unit тестов
Юлия Ковалёва. Fscheck — альтернативный путь для unit тестов
 
UI+unit testing in iOS
UI+unit testing in iOSUI+unit testing in iOS
UI+unit testing in iOS
 
AgileCamp’11 Новосибирск - Test Driven Development (TDD)
AgileCamp’11 Новосибирск - Test Driven Development (TDD)AgileCamp’11 Новосибирск - Test Driven Development (TDD)
AgileCamp’11 Новосибирск - Test Driven Development (TDD)
 
Как сделать ваш JavaScript быстрее
Как сделать ваш JavaScript быстрееКак сделать ваш JavaScript быстрее
Как сделать ваш JavaScript быстрее
 
TDD или как я стараюсь писать код
TDD или как я стараюсь писать кодTDD или как я стараюсь писать код
TDD или как я стараюсь писать код
 
Как сделать ваш JavaScript быстрее / Роман Дворнов (Авито)
Как сделать ваш JavaScript быстрее / Роман Дворнов (Авито)Как сделать ваш JavaScript быстрее / Роман Дворнов (Авито)
Как сделать ваш JavaScript быстрее / Роман Дворнов (Авито)
 
"Outside In". Web application testing.
"Outside In". Web application testing."Outside In". Web application testing.
"Outside In". Web application testing.
 
XP Days Ukraine 2014 - Refactoring legacy code
XP Days Ukraine 2014 - Refactoring legacy codeXP Days Ukraine 2014 - Refactoring legacy code
XP Days Ukraine 2014 - Refactoring legacy code
 
10M tests per day
10M tests per day10M tests per day
10M tests per day
 
Jbreak 2016: Твой личный Spring Boot Starter
Jbreak 2016: Твой личный Spring Boot StarterJbreak 2016: Твой личный Spring Boot Starter
Jbreak 2016: Твой личный Spring Boot Starter
 
kranonit S11E01 Андрей Пономарёв: Тренинг по TDD в Java
kranonit S11E01 Андрей Пономарёв: Тренинг по TDD в Javakranonit S11E01 Андрей Пономарёв: Тренинг по TDD в Java
kranonit S11E01 Андрей Пономарёв: Тренинг по TDD в Java
 
Tdd
TddTdd
Tdd
 
разработка бизнес приложений (8)
разработка бизнес приложений (8)разработка бизнес приложений (8)
разработка бизнес приложений (8)
 
About Python
About PythonAbout Python
About Python
 
Функциональное тестирование высоконагруженных проектов / Илья Пастушков (2ГИС)
Функциональное тестирование высоконагруженных проектов / Илья Пастушков (2ГИС)Функциональное тестирование высоконагруженных проектов / Илья Пастушков (2ГИС)
Функциональное тестирование высоконагруженных проектов / Илья Пастушков (2ГИС)
 
Готовим тестовое окружение, или сколько тестовых инстансов вам нужно / Алекса...
Готовим тестовое окружение, или сколько тестовых инстансов вам нужно / Алекса...Готовим тестовое окружение, или сколько тестовых инстансов вам нужно / Алекса...
Готовим тестовое окружение, или сколько тестовых инстансов вам нужно / Алекса...
 
Повышение качества тестов и автоматическая валидация REST API документации
Повышение качества тестов и автоматическая валидация REST API документацииПовышение качества тестов и автоматическая валидация REST API документации
Повышение качества тестов и автоматическая валидация REST API документации
 

Testing & TDD

  • 2.
  • 3.
  • 4. TDD? ЧТО И ОТКУДА? • Пошло из XP: test-first
  • 5. TDD? ЧТО И ОТКУДА? • Пошло из XP: test-first • Реже используешь отладчик
  • 6. TDD? ЧТО И ОТКУДА? • Пошло из XP: test-first • Реже используешь отладчик • Дизайн еще до реализации
  • 7. TDD? ЧТО И ОТКУДА? • Пошло из XP: test-first • Реже используешь отладчик • Дизайн еще до реализации • Код менее связанный
  • 8. TDD? ЧТО И ОТКУДА? • Пошло из XP: test-first • Реже используешь отладчик • Дизайн еще до реализации • Код менее связанный • Нет сложной инициализации
  • 9. TDD? ЧТО И ОТКУДА? • Пошло из XP: test-first • Реже используешь отладчик • Дизайн еще до реализации • Код менее связанный • Нет сложной инициализации • Интерфейсы четкие и небольшие
  • 10. TDD? ЧТО И ОТКУДА? • Пошло из XP: test-first • Реже используешь отладчик • Дизайн еще до реализации • Код менее связанный • Нет сложной инициализации • Интерфейсы четкие и небольшие • Способствует модульному мышлению !
  • 11. TDD? ЧТО И ОТКУДА? • Нужно привыкнуть
  • 12. TDD? ЧТО И ОТКУДА? • Нужно привыкнуть • На старте может потребовать больше времени
  • 13. TDD? ЧТО И ОТКУДА? • Нужно привыкнуть • На старте может потребовать больше времени • Может возникнуть ложное чувство безопасности
  • 14. TDD? ЧТО И ОТКУДА? • Нужно привыкнуть • На старте может потребовать больше времени • Может возникнуть ложное чувство безопасности • Плохо написанный тест - источник накладных расходов!
  • 15. ПЛАН • Что не так? • Как хочется? • Примеры • Примеры • Примеры • Практика
  • 16. ЧТО ВЫ МОЖЕТЕ СКАЗАТЬ О ТЕСТАХ?
  • 18. Я ненавижу свои тесты ... да и чужие
  • 23. •Медленные •Хрупкие •Что еще хуже - Random’но хрупкие •Дорогие по деньгам
  • 24. •Медленные •Хрупкие •Что еще хуже - Random’но хрупкие •Дорогие по деньгам •Что еще хуже - по времени
  • 25. •Медленные •Хрупкие •Что еще хуже - Random’но хрупкие •Дорогие по деньгам •Что еще хуже - по времени •Хрен поймешь - что тестируют?
  • 26. •Медленные •Хрупкие •Что еще хуже - Random’но хрупкие •Дорогие по деньгам •Что еще хуже - по времени •Хрен поймешь - что тестируют? •Писать и разбираться в них - одна боль и страдание
  • 29. Давайте удалим такие тесты - Что все?
  • 32. UNIT ТЕСТЫ ДОЖНЫ БЫТЬ •Полными
  • 33. UNIT ТЕСТЫ ДОЖНЫ БЫТЬ •Полными •Стабильными
  • 34. UNIT ТЕСТЫ ДОЖНЫ БЫТЬ •Полными •Стабильными •Быстрыми
  • 35. UNIT ТЕСТЫ ДОЖНЫ БЫТЬ •Полными •Стабильными •Быстрыми •Короткими
  • 36. КАК ДЕЛА В КОДЕ НАШИХ ПРОЕКТОВ?
  • 37. КАК ДЕЛА В КОДЕ НАШИХ ПРОЕКТОВ?
  • 38. Давайте подумаем про один какой-нибудь объект...
  • 39.
  • 40. ОБЪЕКТ •Получает что-то от кого-то •Отправляет что-то кому-то •Внутри сам себе покоя не дает
  • 43. Запросы: что-то возвращают и ничего не меняют
  • 44. Запросы: что-то возвращают и ничего не меняют Команды: ничего не возвращают и что-то меняют
  • 45. Запросы: что-то возвращают и ничего не меняют Команды: ничего не возвращают и что-то меняют Избавляйтесь от запросов, которые ведут себя как команды i
  • 46. ЧТО И КАК ТЕСТИРОВАТЬ Запросы Команды Входящие Самому себе Исходящие
  • 48. ВХОДЯЩИЕ ЗАПРОСЫ private class Aggregator {! private readonly int[] _args;! public Aggregator(params int[] args) {! _args = args;! }! public int Sum {! get { return _args.Sum(); }! }! }! !
  • 49. ВХОДЯЩИЕ ЗАПРОСЫ private class Aggregator {! private readonly int[] _args;! public Aggregator(params int[] args) {! _args = args;! }! public int Sum {! get { return _args.Sum(); }! }! }! ! [TestFixture]! public class AggregatorTest {! [Test]! public void Sum() {! var a = new Aggregator(1, 2, 3);! Assert.AreEqual(6, a.Sum);! }! }!
  • 50. ВХОДЯЩИЕ ЗАПРОСЫ Правило 1 ! Тестируем входящие запросы по тому что они возвращают R
  • 51. ВХОДЯЩИЕ ЗАПРОСЫ ! private class MyAverage {! public const int MAGIC_COEF = 2;! private readonly int[] _args;! public MyAverage(params int[] args) {! _args = args;! }! public int Calc() {! return new Aggregator(ModifyArgs).Sum / _args.Length;! }! private int[] ModifyArgs {! get { return _args.Select(a => a * MAGIC_COEF).ToArray(); }! }! }! !
  • 52. ВХОДЯЩИЕ ЗАПРОСЫ ! private class MyAverage {! public const int MAGIC_COEF = 2;! private readonly int[] _args;! public MyAverage(params int[] args) {! _args = args;! }! public int Calc() {! return new Aggregator(ModifyArgs).Sum / _args.Length;! }! private int[] ModifyArgs {! get { return _args.Select(a => a * MAGIC_COEF).ToArray(); }! }! }! ! [TestFixture]! public class MyAverageTest {! [Test]! public void Calc() {! var avg = new MyAverage(10, 20);! Assert.AreEqual(30, avg.Calc());! // Но, там же еще всего так много: MAGIC_COEF, ModifyArgs.! }! }!
  • 53. ВХОДЯЩИЕ ЗАПРОСЫ Правило 2 ! Тестируем интерфейсы, а не конкретную реализацию R
  • 54. ВХОДЯЩИЕ КОМАНДЫ ! private class MyAverage2 : MyAverage {! private int _coef;! ! public void SetCoef(int value) {! _coef = value;! }! ! public int CurrentMagicCoef { get { return _coef + MAGIC_COEF; } }! }! !
  • 55. ВХОДЯЩИЕ КОМАНДЫ ! private class MyAverage2 : MyAverage {! private int _coef;! ! public void SetCoef(int value) {! _coef = value;! }! ! public int CurrentMagicCoef { get { return _coef + MAGIC_COEF; } }! }! ! [TestFixture]! public class MyAverage2Test {! [Test]! public void SetCoef() {! var avg = new MyAverage2();! avg.SetCoef(1);! Assert.AreEqual(3, avg.CurrentMagicCoef);! }! }!
  • 56. ВХОДЯЩИЕ КОМАНДЫ Правило 3 ! Тестируем входящие команды по ближайшему публичному, побочному эффекту R
  • 57. ЧТО И КАК ТЕСТИРОВАТЬ Запросы Команды Входящие Проверка результата Проверка публичного, побочного эффекта Самому себе Исходящие
  • 59. ЗАПРОСЫ К СЕБЕ ! private class MyAverage4 {! public const int MAGIC_COEF = 2;! private readonly int[] _args;! public MyAverage4(params int[] args) {! _args = args;! }! public int Calc() {! return new Aggregator(ModifyArgs).Sum / _args.Length;! }! internal int[] ModifyArgs {! get { return _args.Select(a => a * MAGIC_COEF).ToArray(); }! }! }! ! !
  • 60. ЗАПРОСЫ К СЕБЕ ! private class MyAverage4 {! public const int MAGIC_COEF = 2;! private readonly int[] _args;! public MyAverage4(params int[] args) {! _args = args;! }! public int Calc() {! return new Aggregator(ModifyArgs).Sum / _args.Length;! }! internal int[] ModifyArgs {! get { return _args.Select(a => a * MAGIC_COEF).ToArray(); }! }! }! ! !
  • 61. ЗАПРОСЫ К СЕБЕ ! private class MyAverage4 {! public const int MAGIC_COEF = 2;! private readonly int[] _args;! public MyAverage4(params int[] args) {! _args = args;! }! public int Calc() {! return new Aggregator(ModifyArgs).Sum / _args.Length;! }! internal int[] ModifyArgs {! get { return _args.Select(a => a * MAGIC_COEF).ToArray(); }! }! }! ! [TestFixture]! public class MyAverage4Test {! [Test]! public void ModifyArgs() {! var avg = new MyAverage4(10);! Assert.AreEqual(20, avg.ModifyArgs);! }! }!
  • 62. ЗАПРОСЫ К СЕБЕ ! private class MyAverage4 {! public const int MAGIC_COEF = 2;! private readonly int[] _args;! public MyAverage4(params int[] args) {! _args = args;! }! public int Calc() {! return new Aggregator(ModifyArgs).Sum / _args.Length;! }! internal int[] ModifyArgs {! get { return _args.Select(a => a * MAGIC_COEF).ToArray(); }! }! }! ! [TestFixture]! public class MyAverage4Test {! [Test]! public void ModifyArgs() {! var avg = new MyAverage4(10);! Assert.AreEqual(20, avg.ModifyArgs);! }! }! ТАК ДЕЛАТЬ НЕ НАДО
  • 63. КОМАНДЫ К СЕБЕ ! private class MyAverage5 {! private readonly int[] _args;! internal Aggregator Aggregator;! public MyAverage5(params int[] args) {! _args = args;! }! public int Calc() {! InitAggregator()! return Aggregator.Sum / _args.Length;! }! private void InitAggregator() {! Aggregator = new Aggregator(_args);! }! }!
  • 64. КОМАНДЫ К СЕБЕ ! private class MyAverage5 {! private readonly int[] _args;! internal Aggregator Aggregator;! public MyAverage5(params int[] args) {! _args = args;! }! public int Calc() {! InitAggregator()! return Aggregator.Sum / _args.Length;! }! private void InitAggregator() {! Aggregator = new Aggregator(_args);! }! }! ! [TestFixture]! public class MyAverage5Test {! [Test]! public void Calc() {! var avg = new MyAverage5(10, 20);! Assert.AreEqual(15, avg.Calc());! Assert.IsNotNull(avg.Aggregator);! }! }!
  • 65. КОМАНДЫ К СЕБЕ ! private class MyAverage5 {! private readonly int[] _args;! internal Aggregator Aggregator;! public MyAverage5(params int[] args) {! _args = args;! }! public int Calc() {! InitAggregator()! return Aggregator.Sum / _args.Length;! }! private void InitAggregator() {! Aggregator = new Aggregator(_args);! }! }! ! [TestFixture]! public class MyAverage5Test {! [Test]! public void Calc() {! var avg = new MyAverage5(10, 20);! Assert.AreEqual(15, avg.Calc());! Assert.IsNotNull(avg.Aggregator);! }! }! Этому тут не место
  • 66. КОМАНДЫ К СЕБЕ ! private class MyAverage5 {! private readonly int[] _args;! internal Aggregator Aggregator;! public MyAverage5(params int[] args) {! _args = args;! }! public int Calc() {! InitAggregator()! return Aggregator.Sum / _args.Length;! }! private void InitAggregator() {! Aggregator = new Aggregator(_args);! }! }! ! [TestFixture]! public class MyAverage5Test {! [Test]! public void Calc() {! var avg = new MyAverage5(10, 20);! Assert.AreEqual(15, avg.Calc());! Assert.IsNotNull(avg.Aggregator);! }! }! ТАК ДЕЛАТЬ НЕ НАДО
  • 67. СООБЩЕНИЯ САМОМУ СЕБЕ Правило 4 ! Не тестируйте внутренние методы - не проверяйте их результат - не ожидайте их вызова R
  • 68. ЧТО И КАК ТЕСТИРОВАТЬ Запросы Команды Входящие Проверка результата Проверка публичного, побочного эффекта Самому себе Игнорируем Игнорируем Исходящие
  • 70. ИСХОДЯЩИЕ ЗАПРОСЫ ! public interface IMagicCoef {! int Value { get; }! }! class MagicCoef : IMagicCoef {! public int Value { ! get { return /* Find Magic Value... */ default(int); } }! }! ! private class MyAverage6 {! private readonly IMagicCoef _magic;! private readonly int[] _args;! public MyAverage6(IMagicCoef magic = null, params int[] args) {! _magic = magic ?? new MagicCoef();! _args = args;! }! public int Calc() {! return new Aggregator(ModifyArgs).Sum / _args.Length;! }! private int[] ModifyArgs {! get { return _args.Select(a => a * _magic.Value).ToArray(); }! }! }!
  • 71. ИСХОДЯЩИЕ ЗАПРОСЫ ! public interface IMagicCoef {! int Value { get; }! }! class MagicCoef : IMagicCoef {! public int Value { ! get { return /* Find Magic Value... */ default(int); } }! }! ! private class MyAverage6 {! private readonly IMagicCoef _magic;! private readonly int[] _args;! public MyAverage6(IMagicCoef magic = null, params int[] args) {! _magic = magic ?? new MagicCoef();! _args = args;! }! public int Calc() {! return new Aggregator(ModifyArgs).Sum / _args.Length;! }! private int[] ModifyArgs {! get { return _args.Select(a => a * _magic.Value).ToArray(); }! }! }!
  • 72. ИСХОДЯЩИЕ ЗАПРОСЫ ! class MagicCoef : IMagicCoef {! public int Value { ! get { return /* Find Magic Value... */ default(int); } }! }! ! private class MyAverage6 {! ...! public int Calc() {! return new Aggregator(ModifyArgs).Sum / _args.Length;! }! private int[] ModifyArgs {! get { return _args.Select(a => a * _magic.Value).ToArray(); }! }! }! ! [TestFixture]! public class MyAverage6Test {! [Test]! public void CallMagic() {! var mock = new Mock<IMagicCoef>();! new MyAverage6(mock.Object, 1, 2).Calc();! mock.Verify(m => m.Value, Times.Exactly(2));! }! }! !
  • 73. ИСХОДЯЩИЕ ЗАПРОСЫ ! class MagicCoef : IMagicCoef {! public int Value { ! get { return /* Find Magic Value... */ default(int); } }! }! ! private class MyAverage6 {! ...! public int Calc() {! return new Aggregator(ModifyArgs).Sum / _args.Length;! }! private int[] ModifyArgs {! get { return _args.Select(a => a * _magic.Value).ToArray(); }! }! }! ! [TestFixture]! public class MyAverage6Test {! [Test]! public void CallMagic() {! var mock = new Mock<IMagicCoef>();! new MyAverage6(mock.Object, 1, 2).Calc();! mock.Verify(m => m.Value, Times.Exactly(2));! }! }! ! ТАК ДЕЛАТЬ НЕ НАДО
  • 74. ИСХОДЯЩИЕ ЗАПРОСЫ Правило 5 ! Не тестируйте исходящие запросы - не проверяйте их результат - не ожидайте их вызова R
  • 75. ИСХОДЯЩИЕ ЗАПРОСЫ Правило 5 ! Не тестируйте исходящие запросы - не проверяйте их результат - не ожидайте их вызова R Проверка исходящих запросов добавляет стоимости, но не приносит пользы i
  • 76. ИСХОДЯЩИЕ КОМАНДЫ! ! private class Aggregator7 {! private readonly ILogger _logger;! private readonly int[] _args;! public Aggregator7(ILogger logger = null, params int[] args) {! _logger = logger ?? new LoggerByDb();! _args = args;! }! ! public int Sum {! get {! var sum = _args.Sum();! _logger.LogSum(sum);! return sum;! }! }! }! ! public interface ILogger {! void LogSum(int sum);! }! ! private class LoggerByDb : ILogger {! public void LogSum(int sum) {! // Log sum in data base...! }! }!
  • 77. ИСХОДЯЩИЕ КОМАНДЫ! ! private class Aggregator7 {! private readonly ILogger _logger;! private readonly int[] _args;! public Aggregator7(ILogger logger = null, params int[] args) {! _logger = logger ?? new LoggerByDb();! _args = args;! }! ! public int Sum {! get {! var sum = _args.Sum();! _logger.LogSum(sum);! return sum;! }! }! }! ! public interface ILogger {! void LogSum(int sum);! }! ! private class LoggerByDb : ILogger {! public void LogSum(int sum) {! // Log sum in data base...! }! }!
  • 78. ИСХОДЯЩИЕ КОМАНДЫ! [TestFixture]! public class Aggregator7Test {! [Test]! public void LogTest() {! var sum = new Aggregator7(new LoggerByDb(), 1, 2, 3).Sum;! var logSum = GetLogsFromDb();! Assert.AreEqual(sum, logSum);! }! ! private int GetLogsFromDb() {! // select sum from logtable limit 1;! return default (int);! }! }!
  • 79. ИСХОДЯЩИЕ КОМАНДЫ! [TestFixture]! public class Aggregator7Test {! [Test]! public void LogTest() {! var sum = new Aggregator7(new LoggerByDb(), 1, 2, 3).Sum;! var logSum = GetLogsFromDb();! Assert.AreEqual(sum, logSum);! }! ! private int GetLogsFromDb() {! // select sum from logtable limit 1;! return default (int);! }! }! Это зависимость от «далеких» эффектов и конкретной реализации. Замедляет тесты. i
  • 80. ИСХОДЯЩИЕ КОМАНДЫ! [TestFixture]! public class Aggregator7Test {! [Test]! public void LogTest() {! var sum = new Aggregator7(new LoggerByDb(), 1, 2, 3).Sum;! var logSum = GetLogsFromDb();! Assert.AreEqual(sum, logSum);! }! ! private int GetLogsFromDb() {! // select sum from logtable limit 1;! return default (int);! }! }! Это зависимость от «далеких» эффектов и конкретной реализации. Замедляет тесты. Главное - не имеет отношение к ответственности класса. i
  • 81. ИСХОДЯЩИЕ КОМАНДЫ! [TestFixture]! public class Aggregator7Test {! [Test]! public void LogTest() {! var sum = new Aggregator7(new LoggerByDb(), 1, 2, 3).Sum;! var logSum = GetLogsFromDb();! Assert.AreEqual(sum, logSum);! }! ! private int GetLogsFromDb() {! // select sum from logtable limit 1;! return default (int);! }! }! Это зависимость от «далеких» эффектов и конкретной реализации. Замедляет тесты. Главное - не имеет отношение к ответственности класса. i ТАК ДЕЛАТЬ НЕ НАДО
  • 82. ИСХОДЯЩИЕ КОМАНДЫ! [TestFixture]! public class Aggregator7Test {! // Anti pattern! [Test]! public void BadLogTest() {! var sum = new Aggregator7(new LoggerByDb(), 1, 2, 3).Sum;! var logSum = GetLogsFromDb();! Assert.AreEqual(sum, logSum);! }! ! private int GetLogsFromDb() {! // select sum from logtable limit 1;! return default (int);! }! ! // Good! [Test]! public void GoodLogTest() {! var m = new Mock<ILogger>();! var res = new Aggregator7(m.Object, 1, 2, 3).Sum;! m.Verify(e => e.LogSum(6), Times.Once());! }! }!
  • 83. ИСХОДЯЩИЕ КОМАНДЫ! [TestFixture]! public class Aggregator7Test {! // Anti pattern! [Test]! public void BadLogTest() {! var sum = new Aggregator7(new LoggerByDb(), 1, 2, 3).Sum;! var logSum = GetLogsFromDb();! Assert.AreEqual(sum, logSum);! }! ! private int GetLogsFromDb() {! // select sum from logtable limit 1;! return default (int);! }! ! // Good! [Test]! public void GoodLogTest() {! var m = new Mock<ILogger>();! var res = new Aggregator7(m.Object, 1, 2, 3).Sum;! m.Verify(e => e.LogSum(6), Times.Once());! }! }! Ответственность класса - отправить командуi
  • 84. ИСХОДЯЩИЕ КОМАНДЫ Правило 6 ! Проверяйте отправку исходящих команд с определенными параметрами, но не более того R
  • 85. ИСХОДЯЩИЕ КОМАНДЫ Правило 6 ! Проверяйте отправку исходящих команд с определенными параметрами, но не более того R НО...
  • 86. ИСХОДЯЩИЕ КОМАНДЫ Что будет если интерфейс ILogger захочется изменить?
  • 87. ИСХОДЯЩИЕ КОМАНДЫ Что будет если интерфейс ILogger захочется изменить? БОЛЬ И СТРАДАНИЕ
  • 88. ИСХОДЯЩИЕ КОМАНДЫ Что будет если интерфейс ILogger захочется изменить? БОЛЬ И СТРАДАНИЕ Создавайте «тоникие» интерфейсы. Соблюдайте контракты i
  • 89. ЧТО И КАК ТЕСТИРОВАТЬ Запросы Команды Входящие Проверка результата Проверка публичного, побочного эффекта Самому себе Игнорируем Игнорируем Исходящие Игнорируем Ожидание вызова
  • 96.
  • 97.
  • 98. У каждого есть возможность сказать:
  • 99. У каждого есть возможность сказать: «Я обожаю свои тесты»
  • 101. TDD
  • 103.