Halo pembaca!
Bukan rahasia lagi bahwa pengujian adalah bagian integral dari pengembangan apa pun. Pada artikel sebelumnya, kami melihat arsitektur dasar dari arsitektur Swift Bersih , dan sekarang saatnya untuk belajar bagaimana menutupi Unitnya dengan tes. Kami akan mengambil proyek dari artikel tentang Pekerja sebagai dasar dan menganalisis poin utama.

Teori
Berkat injeksi ketergantungan dan berorientasi protokol , semua komponen adegan dalam Bersihkan Swift saling independen dan dapat diuji secara terpisah. Sebagai contoh, Interactor bergantung pada Presenter dan Worker , tetapi dependensi ini bersifat opsional dan berbasis protokol. Dengan demikian, Interactor dapat melakukan pekerjaannya (meskipun lebih rendah) tanpa Presenter'a dan Worker'a , dan kami juga dapat menggantinya dengan objek lain yang ditandatangani di bawah protokol mereka.
Karena kami ingin menguji setiap komponen secara terpisah, kami perlu mengganti dependensi dengan komponen semu . Ini akan membantu kami menjadi mata-mata (Mata-mata). Mata - mata adalah benda uji yang mengimplementasikan protokol yang ingin kita masukkan dan lacak panggilan metode di dalamnya. Dengan kata lain, kami membuat Spy for Presenter dan Worker , dan kemudian menyuntikkannya ke Interactor untuk melacak panggilan metode.

Dalam keadilan, saya akan menambahkan bahwa ada juga objek uji ( Uji Ganda ) Dummy , Fake , Stub and Mock . Namun dalam kerangka artikel ini, kami tidak akan memengaruhi mereka. Baca lebih lanjut di sini - TestDoubles
Berlatih
Selesai dengan kata-kata, mari kita mulai bisnis. Untuk menghemat waktu Anda, kami akan mempertimbangkan kode abstrak tanpa merinci implementasi dari setiap metode. Rincian kode aplikasi dapat ditemukan di sini: CleanSwiftTests
Untuk setiap komponen adegan, kami membuat file dengan tes dan uji ganda untuk dependensi komponen ( Uji Ganda ).
Contoh struktur seperti itu:

Struktur setiap file tes (untuk komponen) terlihat sama dan mengikuti kira-kira urutan penulisan berikut:
- Kami mendeklarasikan variabel dengan SUT (objek yang akan kami uji) dan variabel dengan dependensi utamanya
- Kami menginisialisasi SUT dan dependensinya di setUp () , lalu menghapusnya di tearDown ()
- Metode pengujian
Seperti yang kita bahas dalam teori, setiap komponen adegan dapat diuji secara terpisah. Kami dapat menyuntikkan duplikat uji ( Spy ) ke dalam dependensinya dan dengan demikian memantau pengoperasian metode SUT kami. Mari kita melihat lebih dekat pada proses penulisan tes menggunakan contoh Interactor dari adegan Home .
HomeInteractor bergantung pada dua objek - Presenter dan Worker . Kedua variabel di kelas memiliki tipe protokol. Ini berarti bahwa kita dapat membuat duplikat uji yang ditandatangani di bawah protokol HomePresentationLogic dan HomeWorkingLogic , dan kemudian menyuntikkannya ke HomeInteractor .
final class HomeInteractor: HomeBusinessLogic, HomeDataStore {
Kami akan menguji dua metode:
- fetchUsers (:) . Bertanggung jawab untuk mendapatkan daftar pengguna dengan API . Permintaan API dikirim menggunakan Pekerja .
- selectUser (:) . Bertanggung jawab untuk memilih pengguna aktif (Pengguna terpilih ) dari daftar pengguna yang dimuat ( pengguna ).
Untuk mulai menulis tes Interactor , kita perlu membuat mata-mata yang akan melacak permohonan metode di HomePresentationLogic dan HomeWorkingLogic . Untuk melakukan ini, buat kelas HomePresentationLogicSpy di direktori 'CleanSwiftTestsTests / Stores / Home / TestDoubles / Spies', tanda tangani protokol HomePresentationLogic dan terapkan metode protokol ini.
final class HomePresentationLogicSpy: HomePresentationLogic {
Semuanya sangat transparan di sini. Jika metode presentFetchedUsers ( HomePresentationLogic ) dipanggil, kami menetapkan nilai variabel isCalledPresentFetchedUsers menjadi true . Dengan demikian, kita dapat melacak apakah metode ini dipanggil selama pengujian Interactor .
Dengan menggunakan prinsip yang sama, buat HomeWorkingLogicSpy . Satu perbedaan, kami sebut selesai , karena bagian dari kode di Interactor akan dibungkus dengan penutupan metode ini. Metode HomeWorkingLogic menangani permintaan jaringan. Kita perlu menghindari permintaan jaringan nyata selama pengujian. Untuk melakukan ini, kami menggantinya dengan uji coba, yang melacak panggilan metode dan mengembalikan data templat, tetapi tidak membuat permintaan apa pun ke jaringan.
final class HomeWorkingLogicSpy: HomeWorkingLogic {
Selanjutnya, kita membuat kelas HomeInteractorTests , yang dengannya kita akan menguji HomeInteractor .
final class HomeInteractorTests: XCTestCase {
Kami menunjukkan tiga variabel utama - sut , pekerja dan presenter .
Di setUp (), inisialisasi objek yang diperlukan, menyuntikkan dependensi di Interactor, dan menetapkan objek ke variabel kelas.
Di tearDown (), kami menghapus variabel kelas untuk kemurnian percobaan.
Metode setUp () dipanggil sebelum metode pengujian dimulai, misalnya testFetchUsers () , dan tearDown () ketika metode ini telah menyelesaikan pekerjaannya. Dengan demikian, kami membuat ulang objek uji ( sut ) sebelum setiap metode pengujian dijalankan.
Selanjutnya adalah metode pengujian sendiri. Struktur ini dibagi menjadi 3 blok logis utama - pembuatan objek yang diperlukan, peluncuran metode yang diuji dalam SUT dan verifikasi hasil. Dalam contoh di bawah ini, kami membuat permintaan (dalam kasus kami, tidak memiliki parameter), jalankan fetchUsers (:) Metode Interactor'a , dan kemudian periksa apakah metode yang diperlukan telah dipanggil di HomeWorkingLogicSpy dan HomePresentationLogicSpy . Kami juga memeriksa apakah Interactor telah menyimpan data uji yang diterima dari Pekerja ke DataStore - nya .
func testFetchUsers() { let request = HomeModels.FetchUsers.Request() sut.fetchUsers(request) XCTAssertTrue(worker.isCalledFetchUsers, "Not started worker.fetchUsers(:)") XCTAssertTrue(presenter.isCalledPresentFetchedUsers, "Not started presenter.presentFetchedUsers(:)") XCTAssertEqual(sut.users.count, worker.users.count) }
Kami akan menguji pilihan pengguna dengan struktur serupa. Kami mendeklarasikan variabel expectationId dan expectationName , dimana kami akan membandingkan hasil pemilihan pengguna. Variabel pengguna menyimpan daftar uji pengguna yang kami tetapkan untuk Interactor . Karena metode pengujian disebut secara independen satu sama lain, dan di tearDown () kita nol data, maka daftar pengguna Interactor kosong dan kita perlu mengisinya dengan sesuatu. Dan kemudian kami memeriksa apakah pengguna ditugaskan di DataStore Interactor'a , setelah memanggil sut.selectUser (:) , dan apakah pengguna itu yang benar.
func testSelectUser() { let expectationId = 2 let expectationName = "Vasya" let users = [ User(id: 1, name: "Ivan", username: "ivan"), User(id: 2, name: "Vasya", username: "vasya91"), User(id: 3, name: "Maria", username: "maria_love") ] let request = HomeModels.SelectUser.Request(index: 1) sut.users = users sut.selectUser(request) XCTAssertNotNil(sut.selectedUser, "User not selected") XCTAssertEqual(sut.selectedUser?.id, expectationId) XCTAssertEqual(sut.selectedUser?.name, expectationName) }
Pengujian Presenter'a dan ViewController'a terjadi pada prinsip yang sama, dengan perbedaan minimal. Salah satu perbedaannya adalah bahwa untuk menguji ViewController, Anda harus membuat UIWindow dan mendapatkan pengontrol dari Storyboard di setUp () , serta membuat objek Spy pada tabel dan koleksi. Namun nuansa ini berbeda dari kebutuhan.
Untuk kelengkapan, saya sarankan Anda membiasakan diri dengan proyek dengan tautan di akhir artikel.
Kesimpulan
Kami telah membahas prinsip-prinsip dasar aplikasi pengujian pada arsitektur Swift Bersih . Itu tidak memiliki perbedaan kuat secara fundamental dari proyek pengujian pada arsitektur lain, semua tes yang sama berlipat ganda, injeksi dan protokol. Hal utama adalah jangan lupa bahwa setiap siklus VIP harus memiliki satu (dan hanya satu!) Tanggung jawab. Ini akan membuat kode lebih bersih dan tes lebih jelas.
Tautan ke proyek: CleanSwiftTests
Bantuan dalam menulis artikel: Bastien
Seri artikel
- Tinjauan Arsitektur Swift Bersih
- Router dan Passing Data dalam Arsitektur Swift Bersih
- Pekerja dalam Arsitektur Swift Bersih
- Unit testing dalam arsitektur Clean Swift (Anda ada di sini)
- Contoh arsitektur toko online sederhana Clean Swift