Содержание
- 2. •СБИС - сеть деловых коммуникаций и обмена электронными документами между компаниями, госорганами и обыкновенными людьми •Свыше
- 3. О чем будем говорить 3 PDF-XChange Editor DEMO PDF-XChange Editor DEMO PDF-XChange Editor DEMO PDF-XChange Editor
- 4. •Принципы создания тестируемого кода О чем будем говорить 4 PDF-XChange Editor DEMO PDF-XChange Editor DEMO PDF-XChange
- 5. •Принципы создания тестируемого кода •Понятие поддельных объектов О чем будем говорить 5 PDF-XChange Editor DEMO PDF-XChange
- 6. •Принципы создания тестируемого кода •Понятие поддельных объектов •Разбор на примере О чем будем говорить 6 PDF-XChange
- 7. •Принципы создания тестируемого кода •Понятие поддельных объектов •Разбор на примере •Общие рекомендации и практические приемы О
- 8. Допущения •Примеры с использованием С++ 8 PDF-XChange Editor DEMO PDF-XChange Editor DEMO PDF-XChange Editor DEMO PDF-XChange
- 9. Допущения •Примеры с использованием С++ •Код упрощен 9 PDF-XChange Editor DEMO PDF-XChange Editor DEMO PDF-XChange Editor
- 10. Допущения •Примеры с использованием С++ •Код упрощен •Используется Google Test https://github.com/google/googletest/tree/master/googletest 10 PDF-XChange Editor DEMO PDF-XChange
- 11. Пример унаследованного кода 11 class EntryAnalyzer { public: bool Analyze( std::string ename ) { if( ename.size()
- 12. class EntryAnalyzer { public: bool Analyze( std::string ename ) { if( ename.size() webService.LogError( "Error: " +
- 13. class EntryAnalyzer { public: bool Analyze( std::string ename ) { if( ename.size() webService.LogError( "Error: " +
- 14. Внешняя зависимость Взаимодействие есть, а контроля нет 14 PDF-XChange Editor DEMO PDF-XChange Editor DEMO PDF-XChange Editor
- 15. Интеграционный тест VS юнит-тест Полный контроль над внешними зависимостями Интеграционный тест Юнит-тест нет да 15 PDF-XChange
- 16. Признаки хорошего юнит-теста Полный контроль над внешними зависимостями 16 Результат PDF-XChange Editor DEMO PDF-XChange Editor DEMO
- 17. Признаки хорошего юнит-теста Полный контроль над внешними зависимостями Результат •стабилен 17 PDF-XChange Editor DEMO PDF-XChange Editor
- 18. Признаки хорошего юнит-теста Полный контроль над внешними зависимостями Результат •стабилен •повторим 18 PDF-XChange Editor DEMO PDF-XChange
- 19. Признаки хорошего юнит-теста Полный контроль над внешними зависимостями Результат •стабилен •повторим •независим 19 PDF-XChange Editor DEMO
- 20. Признаки хорошего юнит-теста Полный контроль над внешними зависимостями Автоматизация запуска Результат •стабилен •повторим •независим 20 PDF-XChange
- 21. Признаки хорошего юнит-теста Полный контроль над внешними зависимостями Автоматизация запуска Результат •стабилен •повторим •независим •Малое время
- 22. Признаки хорошего юнит-теста Полный контроль над внешними зависимостями Автоматизация запуска Результат •стабилен •повторим •независим •Малое время
- 23. Признаки хорошего юнит-теста Полный контроль над внешними зависимостями Автоматизация запуска Результат •стабилен •повторим •независим •Малое время
- 24. Исходный код class EntryAnalyzer { public: bool Analyze( std::string ename ) { if( ename.size() webService.LogError( "Error:
- 25. Исходный код class WebService { public: void LogError( std::string msg ) { /* логика, включающая работу
- 26. Исходный код class WebService { public: void LogError( std::string msg ) { /* логика, включающая работу
- 27. Исходный код Внешние зависимости 27 class EntryAnalyzer { public: bool Analyze( std::string ename ) { if(
- 28. Как сделать унаследованный код тестируемым? 28 PDF-XChange Editor DEMO PDF-XChange Editor DEMO PDF-XChange Editor DEMO PDF-XChange
- 29. Понятие программного шва •Шов — место в котором можно изменить поведение программы, не правя ее в
- 30. Слои тестирования 30 Препроцессор Компилятор Компоновщик Run-time PDF-XChange Editor DEMO PDF-XChange Editor DEMO PDF-XChange Editor DEMO
- 31. Слои тестирования 31 Препроцессор Компилятор Компоновщик Run-time Модифицированный исходный код PDF-XChange Editor DEMO PDF-XChange Editor DEMO
- 32. Слои тестирования 32 Препроцессор Компилятор Компоновщик Run-time Модифицированный исходный код Машинный код PDF-XChange Editor DEMO PDF-XChange
- 33. Слои тестирования 33 Препроцессор Компилятор Компоновщик Run-time Модифицированный исходный код Исполняемый файл Машинный код PDF-XChange Editor
- 34. Слои тестирования 34 Препроцессор Компилятор Компоновщик Run-time Модифицированный исходный код Исполняемый файл Машинный код Выполнение приложения
- 35. Слои тестирования 35 Препроцессор Компилятор Компоновщик Run-time Шов предварительной обработки Исполняемый файл Машинный код Выполнение приложения
- 36. Слои тестирования 36 Препроцессор Компилятор Компоновщик Run-time Шов предварительной обработки Шов этапа компиляции Исполняемый файл Машинный
- 37. Слои тестирования 37 Препроцессор Компилятор Компоновщик Run-time Шов предварительной обработки Шов этапа компиляции Компоновочный шов Исполняемый
- 38. Слои тестирования 38 Препроцессор Компилятор Компоновщик Run-time Шов предварительной обработки Шов этапа компиляции Компоновочный шов Объектный
- 39. Слои тестирования 39 Препроцессор Компилятор Компоновщик Run-time Шов предварительной обработки Шов этапа компиляции Компоновочный шов Объектный
- 40. Слои тестирования 40 Препроцессор Компилятор Компоновщик Run-time Шов предварительной обработки Шов этапа компиляции Компоновочный шов Объектный
- 41. Слои тестирования 41 Препроцессор Компилятор Компоновщик Run-time Шов предварительной обработки Шов этапа компиляции Компоновочный шов Объектный
- 42. Слои тестирования 42 Препроцессор Компилятор Компоновщик Run-time Шов предварительной обработки Шов этапа компиляции Компоновочный шов Объектный
- 43. Признаки хорошего юнит-теста Полный контроль над внешними зависимостями Автоматизация запуска Результат •стабилен •повторим •независим •Малое время
- 44. Принцип наименования юнит-теста Sum_ByDefault_ReturnsZero() Sum_WhenCalled_CallsTheLogger() [ИмяТестируемойРабочейЕдиницы]_ [СценарийТеста]_ [ОжидаемыйРезультат] 44 PDF-XChange Editor DEMO PDF-XChange Editor DEMO PDF-XChange
- 45. TEST_F( CalculatorTest, Sum_ByDefault_ReturnsZero ) { Calculator calc; int last_sum = calc.Sum(); ASSERT_EQ( 0, last_sum ); }
- 46. TEST_F( CalculatorTest, Sum_ByDefault_ReturnsZero ) { Calculator calc; int last_sum = calc.Sum(); ASSERT_EQ( 0, last_sum ); }
- 47. TEST_F( CalculatorTest, Sum_ByDefault_ReturnsZero ) { Calculator calc; int last_sum = calc.Sum(); ASSERT_EQ( 0, last_sum ); }
- 48. TEST_F( CalculatorTest, Sum_ByDefault_ReturnsZero ) { Calculator calc; int last_sum = calc.Sum(); ASSERT_EQ( 0, last_sum ); }
- 49. TEST_F( CalculatorTest, Sum_ByDefault_ReturnsZero ) { Calculator calc; int last_sum = calc.Sum(); ASSERT_EQ( 0, last_sum ); }
- 50. Понятие поддельных объектов 50 PDF-XChange Editor DEMO PDF-XChange Editor DEMO PDF-XChange Editor DEMO PDF-XChange Editor DEMO
- 51. Поддельные реализации объектов Fake-объект Stub-объект Задача ра зделения Mock-объект Задача ра спознавания 51 PDF-XChange Editor DEMO
- 52. Stub-объект Взаимоде йствие Тестовый код Тестируемый код Stub Взаимодействие 52 PDF-XChange Editor DEMO PDF-XChange Editor DEMO
- 53. Mock-объект Взаимоде йствие Тестовый код Тестируемый код Mock Взаимодействие 53 PDF-XChange Editor DEMO PDF-XChange Editor DEMO
- 54. Слои тестирования 54 Препроцессор Компилятор Компоновщик Run-time Шов предварительной обработки Шов этапа компиляции Компоновочный шов Объектный
- 55. Объектный шов •Разрешающая точка находится на этапе создания объектов •Выбор стратегии выполнения действия в зависимости от
- 56. Объектный шов База данных TestingDatabaseManager DatabaseManager 56 Режим Тестирования? Да Нет PDF-XChange Editor DEMO PDF-XChange Editor
- 57. Использование stub для разрыва зависимости “Выделить и переопределить” 57 PDF-XChange Editor DEMO PDF-XChange Editor DEMO PDF-XChange
- 58. class EntryAnalyzer { public: bool Analyze( std::string ename ) { if( ename.size() webService.LogError( "Error: " +
- 59. class EntryAnalyzer { public: bool Analyze( std::string ename ) { ... return IsValid( ename ); }
- 60. class EntryAnalyzer { public: bool Analyze( std::string ename ) { ... return IsValid( ename ); }
- 61. Переопределение зависимости class TestingEntryAnalyzer : public EntryAnalyzer { public: bool willBeValid; private: bool IsValid( std::string ename
- 62. Переопределение зависимости class TestingEntryAnalyzer : public EntryAnalyzer { public: bool willBeValid; private: bool IsValid( std::string ename
- 63. Переопределение зависимости class TestingEntryAnalyzer : public EntryAnalyzer { public: bool willBeValid; private: bool IsValid( std::string ename
- 64. Тестирование возвращаемого значения TEST_F( EntryAnalyzerTest, Analyze_ValidEntryName_ReturnsTrue) { TestingEntryAnalyzer ea; ea.willBeValid = true; bool result = ea.Analyze(
- 65. Тестирование возвращаемого значения TEST_F( EntryAnalyzerTest, Analyze_ValidEntryName_ReturnsTrue) { TestingEntryAnalyzer ea; ea.willBeValid = true; bool result = ea.Analyze(
- 66. 66 class TestingEntryAnalyzer : public EntryAnalyzer { public: TestingEntryAnalyzer() { } bool willBeValid; }; class EntryAnalyzer
- 67. Возможные проблемы при переопределении зависимости 67 class TestingEntryAnalyzer : public EntryAnalyzer { public: TestingEntryAnalyzer() { }
- 68. Использование stub для разрыва зависимости Параметризация конструктора. 68 PDF-XChange Editor DEMO PDF-XChange Editor DEMO PDF-XChange Editor
- 69. Разрыв зависимости от базы данных База данных bool IsValid( std::string ename ) IDatabaseManager FakeDatabaseManager DatabaseManager 69
- 70. Разрыв зависимости от базы данных 70 class IDatabaseManager { public: virtual bool IsValid( std::string ename )
- 71. class IDatabaseManager { public: virtual bool IsValid( std::string ename ) = 0; }; class FakeDatabaseManager :
- 72. class DatabaseManager : public IDatabaseManager { public: bool IsValid( std::string ename ) { /* сложная логика,
- 73. Вместо конкретной реализации – интерфейс class EntryAnalyzer { public: bool Analyze( std::string ename ) { if(
- 74. Вместо конкретной реализации – интерфейс class EntryAnalyzer { public: EntryAnalyzer() : pDbManager( std::make_unique () ) {
- 75. Вместо конкретной реализации – интерфейс class EntryAnalyzer { public: EntryAnalyzer() : pDbManager( std::make_unique () ) {
- 76. Вместо конкретной реализации – интерфейс class EntryAnalyzer { public: EntryAnalyzer() : pDbManager( std::make_unique () ) {
- 77. Разрыв зависимости от базы данных 77 class IDatabaseManager { public: virtual bool IsValid( std::string ename )
- 78. class IDatabaseManager { public: virtual bool IsValid( std::string ename ) = 0; virtual ~IDatabaseManager() = default;
- 79. class IDatabaseManager { public: virtual bool IsValid( std::string ename ) = 0; virtual ~IDatabaseManager() = default;
- 80. class DatabaseManager : public IDatabaseManager { public: bool IsValid( std::string ename ) override { /* сложная
- 81. class DatabaseManager : public IDatabaseManager { public: bool IsValid( std::string ename ) override { /* сложная
- 82. class DatabaseManager : public IDatabaseManager { public: bool IsValid( std::string ename ) override { /* сложная
- 83. Внедрение зависимости class EntryAnalyzer { public: EntryAnalyzer( std::unique_ptr &&p_db_mng ) : pDbManager( std::move( p_db_mng ) )
- 84. class EntryAnalyzer { public: EntryAnalyzer( std::unique_ptr &&p_db_mng ) : pDbManager( std::move( p_db_mng ) ) { }
- 85. class EntryAnalyzer { public: EntryAnalyzer( std::unique_ptr &&p_db_mng ) : pDbManager( std::move( p_db_mng ) ) { }
- 86. class EntryAnalyzer { public: EntryAnalyzer() : pDbManager( std::make_unique () ) { } bool Analyze( std::string ename
- 87. class EntryAnalyzer { public: EntryAnalyzer() : pDbManager( std::make_unique () ) { } bool Analyze( std::string ename
- 88. class EntryAnalyzer { public: EntryAnalyzer( std::unique_ptr &&p_mng = std::make_unique () ) : pDbManager( std::move( p_mng )
- 89. class EntryAnalyzer { public: EntryAnalyzer( std::unique_ptr &&p_mng = std::make_unique () ) : pDbManager( std::move( p_mng )
- 90. Тестирование возвращаемого значения TEST_F( EntryAnalyzerTest, Analyze_ValidEntryName_ReturnsTrue ) { EntryAnalyzer ea( std::make_unique ( true ) ); bool
- 91. Тестирование возвращаемого значения class FakeDatabaseManager : public IDatabaseManager { public: bool willBeValid; FakeDatabaseManager( bool will_be_valid )
- 92. Разбор на примере 92 PDF-XChange Editor DEMO PDF-XChange Editor DEMO PDF-XChange Editor DEMO PDF-XChange Editor DEMO
- 93. Исходный код 93 class Analyzer { public: int Analyze() { if( false == WinAPIFind() ) return
- 94. Исходный код 94 class Analyzer { public: int Analyze() { if( false == WinAPIFind() ) return
- 95. Локализация внешних зависимостей 95 class Analyzer { public: int Analyze() { if( false == WinAPIFind() )
- 96. Подготовка к разрыву зависимости 96 class Analyzer { public: int Analyze() { if( false == Find()
- 97. Подготовка к разрыву зависимости 97 class Analyzer { public: int Analyze() { if( false == Find()
- 98. Вводим класс-наследник 98 class TestingAnalyzer : public Analyzer { public: bool findApiCallWillBeReturned; bool procApiCallWillBeReturned; private: virtual
- 99. Вводим класс-наследник 99 class TestingAnalyzer : public Analyzer { public: bool findApiCallWillBeReturned; bool procApiCallWillBeReturned; private: virtual
- 100. Вводим класс-наследник 100 class TestingAnalyzer : public Analyzer { public: bool findApiCallWillBeReturned; bool procApiCallWillBeReturned; private: virtual
- 101. Покрываем существующую логику работы класса юнит-тестами 101 Analyze_WhenFindFails_Returns1() { TestingAnalyzer tf; tf.findApiCallWillBeReturned = false; int test_ret
- 102. Покрываем существующую логику работы класса юнит-тестами 102 Analyze_WhenFindFails_Returns1() { TestingAnalyzer tf; tf.findApiCallWillBeReturned = false; int test_ret
- 103. Покрываем существующую логику работы класса юнит-тестами 103 Analyze_WhenFindFails_Returns1() { TestingAnalyzer tf; tf.findApiCallWillBeReturned = false; int test_ret
- 104. Вносим изменения в боевой класс 104 class Analyzer { public: int Analyze() { if( false ==
- 105. Вносим изменения в боевой класс 105 class Analyzer { public: int Analyze() { if( false ==
- 106. Вносим изменения в боевой класс 106 class Analyzer { public: int Analyze() { if( false ==
- 107. Поиск внешних зависимостей 107 class Analyzer { public: int Analyze() { if( false == Find() )
- 108. Поиск внешних зависимостей 108 class Analyzer { public: int Analyze() { if( false == Find() )
- 109. Подготовка к разрыву зависимости 109 class IWindowsProcessor { virtual int Process() = 0; virtual ~IWindowsProcessor() =
- 110. Подготовка к разрыву зависимости 110 class IWindowsProcessor { virtual int Process() = 0; virtual ~IWindowsProcessor() =
- 111. Подготовка к разрыву зависимости 111 class IWindowsProcessor { virtual int Process() = 0; virtual ~IWindowsProcessor() =
- 112. Подготовка к разрыву зависимости 112 class Analyzer { public: int Analyze() { WindowsProcessor wp; return wr.Process();
- 113. Подготовка к разрыву зависимости 113 class Analyzer { public: Analyzer() : pWindowsProcessor( nullptr ) { pWindowsProcessor
- 114. Внедрение зависимости 114 class Analyzer { public: Analyzer() : pWindowsProcessor( nullptr ) { pWindowsProcessor = std::make_unique
- 115. Внедрение зависимости 115 class Analyzer { public: Analyzer() : pWindowsProcessor( nullptr ) { pWindowsProcessor = std::make_unique
- 116. Обновление тестов 116 Analyze_WhenFindFails_Returns1() { Analyzer f; std::unique_ptr p_twp = std::make_unique (); p_twp->findApiCallWillBeReturned = false; SetWindowsProcessor(
- 117. Обновление тестов 117 Analyze_WhenFindFails_Returns1() { TestingAnalyzer tf; tf.findApiCallWillBeReturned = false; int test_ret = tf.Analyze(); int etalon_ret
- 118. Обновление тестов 118 Analyze_WhenFindFails_Returns1() { Analyzer f; std::unique_ptr p_twp = std::make_unique (); p_twp->findApiCallWillBeReturned = false; SetWindowsProcessor(
- 119. Обновление тестов 119 Analyze_WhenFindFails_Returns1() { Analyzer f; std::unique_ptr p_twp = std::make_unique (); p_twp->findApiCallWillBeReturned = false; SetWindowsProcessor(
- 120. Обновление тестов 120 Analyze_WhenFindFails_Returns1() { Analyzer f; std::unique_ptr p_twp = std::make_unique (); p_twp->findApiCallWillBeReturned = false; f.SetWindowsProcessor(
- 121. Обновление тестов 121 Analyze_WhenFindFails_Returns1() { Analyzer f; std::unique_ptr p_twp = std::make_unique (); p_twp->findApiCallWillBeReturned = false; f.SetWindowsProcessor(
- 122. Обновление тестов 122 Analyze_WhenFindFails_Returns1() { Analyzer f; std::unique_ptr p_twp = std::make_unique (); p_twp->findApiCallWillBeReturned = false; f.SetWindowsProcessor(
- 123. Обновление тестов 123 Analyze_WhenProcFails_Returns2() { Analyzer f; std::unique_ptr p_twp = std::make_unique (); p_twr->findApiCallWillBeReturned = true; p_twr->procApiCallWillBeReturned
- 124. Обновление тестов 124 Analyze_WhenSucceeded_Returns0() { Analyzer f; std::unique_ptr p_twp = std::make_unique (); p_twr->findApiCallWillBeReturned = true; p_twr->procApiCallWillBeReturned
- 125. Общие рекомендации и практические приемы 125 PDF-XChange Editor DEMO PDF-XChange Editor DEMO PDF-XChange Editor DEMO PDF-XChange
- 126. Рекомендации •Общий принцип: рефакторинг кода с целью локализации мест обращения к внешним зависимостям 126 PDF-XChange Editor
- 127. Рекомендации •Общий принцип: рефакторинг кода с целью локализации мест обращения к внешним зависимостям •Сохраняем сигнатуры методов
- 128. Практические приемы 128 PDF-XChange Editor DEMO PDF-XChange Editor DEMO PDF-XChange Editor DEMO PDF-XChange Editor DEMO PDF-XChange
- 129. Практические приемы • Один тест — один результат работы 129 PDF-XChange Editor DEMO PDF-XChange Editor DEMO
- 130. Практические приемы 130 TEST_F( EntryAnalyzerTest, Analyze_TooShortEntryName_ReturnsFalseLoggsErrorToWebServer ) { TestingEntryAnalyzer ea; bool is_valid = ea.Analyze( "e" );
- 131. Практические приемы 131 TEST_F( EntryAnalyzerTest, Analyze_TooShortEntryName_ReturnsFalseLoggsErrorToWebServer ) { TestingEntryAnalyzer ea; bool is_valid = ea.Analyze( "e" );
- 132. Практические приемы 132 TEST_F( EntryAnalyzerTest, Analyze_TooShortEntryName_ReturnsFalseLoggsErrorToWebServer ) { TestingEntryAnalyzer ea; bool is_valid = ea.Analyze( "e" );
- 133. Практические приемы 133 TEST_F( EntryAnalyzerTest, Analyze_TooShortEntryName_ReturnsFalseLoggsErrorToWebServer ) { TestingEntryAnalyzer ea; bool is_valid = ea.Analyze( "e" );
- 134. Практические приемы 134 TEST_F( EntryAnalyzerTest, Analyze_TooShortEntryName_ReturnsFalseLoggsErrorToWebServer ) { TestingEntryAnalyzer ea; bool is_valid = ea.Analyze( "e" );
- 135. Практические приемы 135 TEST_F( EntryAnalyzerTest, Analyze_TooShortEntryName_ReturnsFalseLoggsErrorToWebServer ) { TestingEntryAnalyzer ea; bool is_valid = ea.Analyze( "e" );
- 136. Практические приемы • Один тест — один результат работы 136 PDF-XChange Editor DEMO PDF-XChange Editor DEMO
- 137. Практические приемы • Один тест — один результат работы • Тестируем только публичные методы 137 PDF-XChange
- 138. Практические приемы • Один тест — один результат работы • Тестируем только публичные методы • Нет
- 139. Практические приемы • Один тест — один результат работы • Тестируем только публичные методы • Нет
- 140. Практические приемы • Один тест — один результат работы • Тестируем только публичные методы • Нет
- 141. Практические приемы 141 TEST_F( EntryAnalyzerTest, Analyze_Condition1_ReturnsTrue ) { EntryAnalyzer ea; ea.Analyze( "name1" ); … } TEST_F(
- 142. Практические приемы 142 TEST_F( EntryAnalyzerTest, Analyze_Condition1_ReturnsTrue ) { EntryAnalyzer ea; ea.Analyze( "name1" ); … } TEST_F(
- 143. Практические приемы 143 TEST_F( EntryAnalyzerTest, Analyze_Condition1_ReturnsTrue ) { EntryAnalyzer ea; ea.Analyze( “name1" ); … } TEST_F(
- 144. Практические приемы 144 TEST_F( EntryAnalyzerTest, Analyze_Condition1_ReturnsTrue ) { EntryAnalyzer ea; ea.Analyze( “name1" ); … } TEST_F(
- 145. Практические приемы 145 TEST_F( EntryAnalyzerTest, Analyze_Condition1_ReturnsTrue ) { EntryAnalyzer ea; ea.Analyze( “name1" ); … } TEST_F(
- 146. Практические приемы 146 TEST_F( EntryAnalyzerTest, Analyze_Condition1_ReturnsTrue ) { EntryAnalyzer ea; ea.Analyze( “name1" ); … } TEST_F(
- 147. Практические приемы • Один тест — один результат работы • Тестируем только публичные методы • Нет
- 148. Где почитать подробнее • Майкл Физерс “Эффективная работа с унаследованным кодом” 148 PDF-XChange Editor DEMO PDF-XChange
- 149. Где почитать подробнее • Майкл Физерс “Эффективная работа с унаследованным кодом” •Roy Osherove “The art of
- 151. Скачать презентацию