2. Что такое unit тесты
Для чего тестировать
Когда тестировать
Виды unit тестов
Двойники для тестов
Управление зависимостями
Лучшие практики
Тезисы
3. Что такое unit тесты ?
Модульное тестирование, или юнит-тестирование (англ.
unit testing) — процесс в программировании, позволяющий
проверить на корректность отдельные модули исходного
кода программы.
Википедия
4. Что такое unit тесты ?
Класс Тест класс
Метод 1
Метод 2
Тест метод 1.2
Тест метод 2.1
Тест метод 1.1
.
.
.
5. Для чего тестировать ?
Уверенность в корректности работы программы
Возможность рефакторинга
Исполняемая документация
Исполняемые требования
Работа с CI системами
Доказательство что баг исправлен
14. // Менеджер ресторана должен сказать нам какой стол свободен
struct Manager{
// Он обращается к сервису реализующему протокол
var tablesService: FreeTableProvider
func getFreeTable() -> Int{
let tableId = tablesService.getTable()
return tableId
}
// Constructor injection
init(tablesService: FreeTableProvider = ProductionTableProvider()){
self.tablesService = tablesService
}
}
// Протокол для сервиса
protocol FreeTableProvider{
func getTable() -> Int
}
struct ProductionTableProvider: FreeTableProvider{
func getTable() -> Int {
let tableId = makeLongRunningRequestAndReturnTable()
return tableId
}
private func makeLongRunningRequestAndReturnTable() -> Int { . . . }
}
15. class StubFreeTableProvider: FreeTableProvider{
func getTable() -> Int { return 42 }
}
class ManagerTests: XCTestCase {
override func setUp() {
super.setUp()
}
override func tearDown() {
super.tearDown()
}
func testManagerRetunsFreeTable(){
let stubFreeTableProvider = StubFreeTableProvider()
let manager = Manager(tablesService: stubFreeTableProvider)
let tableId = manager.getFreeTable()
XCTAssertEqual(tableId, 42, "Менеджер возвращает столик полученный от сервиса")
}
}
16. protocol OrderExecutor{
func executeOrder()
}
// Теперь мы тестируем внутреннее состояние официанта
struct Waiter{
// Столик с которым работает официант
var currentTableId: Int?
var cook: OrderExecutor
func excecuteOrder(){
cook.executeOrder()
}
// Функция позвать официанта к столику
mutating func call(toTable tableId: Int){
currentTableId = tableId
}
init(orderExecutor: OrderExecutor){
self.cook = orderExecutor
}
}
17. class WaiterUnitTests: XCTestCase {
override func setUp() {
super.setUp()
}
override func tearDown() {
super.tearDown()
}
func testWaiterServesTableAfterCalling(){
var waiter = Waiter()
let tableId = 42
waiter.call(toTable: tableId)
XCTAssertEqual(tableId, waiter.currentTableId, "Официанта приходит к столику")
}
}
18. // Тот кто реализует этот протокол может исполнять заказы
protocol OrderExecutor{
func executeOrder()
}
// Теперь поведение официанта
struct Waiter{
var currentTableId: Int?
// Тот кто реализует этот протокол может исполнять заказы
var cook: OrderExecutor
// Функция передать заказ повару
func excecuteOrder(){
cook.executeOrder()
}
mutating func call(toTable tableId: Int){
currentTableId = tableId
}
// Constructor injection
init(orderExecutor: OrderExecutor = ProductionOrderExecutor()){
self.cook = orderExecutor
}
}
19. class MockCook: OrderExecutor{
var isOrederExecuted = false
func executeOrder() {
isOrederExecuted = true
}
}
class WaiterUnitTests: XCTestCase {
func testWaiterGivesOrderToCook(){
let mockCook = MockCook()
let waiter = Waiter(orderExecutor: mockCook)
waiter.excecuteOrder()
XCTAssertTrue(mockCook.isOrederExecuted, "Официант отдал заказ повару”)
}
}
20. Лучшие практики
DRY
if, switch, for, while
Сложные setUp
Вычисляемые ожидаемые значения
Много assert на тест
Мало тестов
Много тестов