Чистые тесты на swift
TRANSCRIPT
What makes a clean test?
Three things. Readability, readability, and readability.
Robert C. Martin, «Clean Code»
Assertions
public func XCTFail(_ message: String = default, file: StaticString = #file, line: UInt = #line)
Assertions
func testExample() { // given let pair = (20, 16)
// when
// then XCTAssertEqual(pair, (20, 17)) }
Assertions
func testExample() { // given let pair = (20, 16)
// when
// then XCTAssertEqual(pair, (20, 17)) }
Assertions
func testExample() { // given let pair = (20, 16)
// when
// then XCTAssert(pair == (20, 17)) }
Custom assertions
func assertIntPairsEqual(actual: (_: Int, _: Int), expected: (_: Int, _: Int), file: StaticString = #file, line: UInt = #line) { if actual != expected { XCTFail("Expected \(expected) but was \(actual)", file: file, line: line) } }
Custom assertions
func assertIntPairsEqual(actual: (_: Int, _: Int), expected: (_: Int, _: Int), file: StaticString = #file, line: UInt = #line) { if actual != expected { XCTFail("Expected \(expected) but was \(actual)", file: file, line: line) } }
Custom assertions
func assertIntPairsEqual(actual: (_: Int, _: Int), expected: (_: Int, _: Int), file: StaticString = #file, line: UInt = #line) { if actual != expected { XCTFail("Expected \(expected) but was \(actual)", file: file, line: line) } }
Custom assertions
func assertPairsEqual<T: Equatable, U: Equatable>(actual: (_: T, _: U), expected: (_: T, _: U), file: StaticString = #file, line: UInt = #line)
Mocks
struct ToDoService {
init(session: URLSession) { // … }}
let service = ToDoService(session: URLSession.shared)
Mocks
struct ToDoService {
init(session: URLSession) { // … }}
let service = ToDoService(session: URLSession.shared)
Mocks
protocol URLSessionProtocol {}extension URLSession: URLSessionProtocol {}
struct ToDoService {
init(session: URLSessionProtocol) { // … }}
Mocks
protocol URLSessionProtocol {}extension URLSession: URLSessionProtocol {}
struct ToDoService {
init(session: URLSessionProtocol) { // … }}
Mocks
protocol URLSessionProtocol {}extension URLSession: URLSessionProtocol {}
struct ToDoService {
init(session: URLSessionProtocol) { // … }}
Mocks
protocol URLSessionProtocol {}extension URLSession: URLSessionProtocol {}
struct ToDoService {
init(session: URLSessionProtocol) { // … }}
Mocks
protocol URLSessionProtocol {
func dataTask(request: URLRequest, completion:(Data?, Response?, Error?) -> Swift.Void) -> DataTask
}
Mocks
class MockURLSession: URLSessionProtocol {
func dataTask(with …) -> URLSessionDataTask { return URLSessionDataTask() }}
Mocks
class MockURLSession: URLSessionProtocol { var dataTaskCallCount = 0
func dataTask(with …) -> URLSessionDataTask { dataTaskCallCount += 1 return URLSessionDataTask() }}
Mocks
func testExample() { // given
...
// when ...
// then XCTAssertEqual(mockURLSession.dataTaskCallCount, 1)}
Mocks
class MockURLSession: URLSessionProtocol { var dataTaskLastURL: URL?
func dataTask(with …) -> URLSessionDataTask { dataTaskLastURL = url return URLSessionDataTask() }}
Mocksfunc testExample() { // given
...
// when ...
// then XCTAssertEqual(mockURLSession.dataTaskLastURL?.host, "http://expected.com")}
Mocks
1. Используйте вспомогательные методы для одной проверки
2. Накапливайте аргументы в коллекциях
Partial mocksclass MockURLSessionDataTask: URLSessionDataTask { private var resumeCallCount = 0
override func resume() { resumeCallCount += 1 }
func verifyResume() { XCTAssertEqual(resumeCallCount, 1) }}
Partial mocksclass MockURLSession: URLSessionProtocol { var dataTaskReturnValue: URLSessionDataTask!
func dataTask(with …) -> URLSessionDataTask { return dataTaskReturnValue }}
Partial mocks func testExample() { // given let mockDataTask = MockURLSessionDataTask() mockURLSession.dataTaskReturnValue = mockDataTask
// when …
// then mockDataTask.verifyResume() }
1.Чистые тесты должны оставаться чистыми
2.Используйте коллекции вспомогательных методов
3.Добавляйте методы проверок к мокам
4.Используйте #file и #line
5.Не мокируйте value types
1.Чистые тесты должны оставаться чистыми
2.Используйте коллекции вспомогательных методов
3.Добавляйте методы проверок к мокам
4.Используйте #file и #line
5.Не мокируйте value types
@asychev89