unit testing ios applications

21
Unit тестирование iOS приложений Андрей Волобуев

Upload: andrey-volobuev

Post on 14-Apr-2017

177 views

Category:

Software


0 download

TRANSCRIPT

Page 1: Unit testing iOS Applications

Unit тестирование iOS приложений

Андрей Волобуев

Page 2: Unit testing iOS Applications

Что такое unit тесты

Для чего тестировать

Когда тестировать

Виды unit тестов

Двойники для тестов

Управление зависимостями

Лучшие практики

Тезисы

Page 3: Unit testing iOS Applications

Что такое unit тесты ?

Модульное тестирование, или юнит-тестирование (англ. unit testing) — процесс в программировании, позволяющий проверить на корректность отдельные модули исходного кода программы.

Википедия

Page 4: Unit testing iOS Applications

Что такое unit тесты ?Класс Тест класс

Метод 1

Метод 2

Тест метод 1.2

Тест метод 2.1

Тест метод 1.1

.

.

.

Page 5: Unit testing iOS Applications

Для чего тестировать ?

Уверенность в корректности работы программы

Возможность рефакторинга

Исполняемая документация

Исполняемые требования

Работа с CI системами

Доказательство что баг исправлен

Page 6: Unit testing iOS Applications

Когда тестировать ?TDD - сначала пишется тест

Refactor

Red

Green

Page 7: Unit testing iOS Applications

Когда тестировать ?

Обычное тестирование - тесты пишутся после кода

Page 8: Unit testing iOS Applications

Когда тестировать

Вопрос в том насколько после

Page 9: Unit testing iOS Applications

Виды unit тестов

Возвращаемый результат

Состояние

Поведение

Page 10: Unit testing iOS Applications

Двойники для тестов

Клиент Официант Повар

Ресторан

Page 11: Unit testing iOS Applications

Двойники для тестов

Клиент Официант Тест повар

Ресторан

Page 12: Unit testing iOS Applications

Двойники для тестов

Stub - возвращают заранее предопределенный результат

Mock - содержат логику для проверки поведения

Page 13: Unit testing iOS Applications

Управление зависимостями

Dependency injection

Page 14: Unit testing iOS Applications

// Менеджер ресторана должен сказать нам какой стол свободен 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 { . . . } }

Page 15: Unit testing iOS Applications

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, "Менеджер возвращает столик полученный от сервиса") } }

Page 16: Unit testing iOS Applications

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 } }

Page 17: Unit testing iOS Applications

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, "Официанта приходит к столику") } }

Page 18: Unit testing iOS Applications

// Тот кто реализует этот протокол может исполнять заказы 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 } }

Page 19: Unit testing iOS Applications

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, "Официант отдал заказ повару”) } }

Page 20: Unit testing iOS Applications

Лучшие практики DRY

if, switch, for, while

Сложные setUp

Вычисляемые ожидаемые значения

Много assert на тест

Мало тестов

Много тестов

Page 21: Unit testing iOS Applications

ВОПРОСЫ?