Skip to content
  • Home
  • Code
  • iOS & Swift
  • Combine
  • RxSwift
  • SwiftUI
  • Flutter & Dart
  • Tutorials
  • Art
  • Blog
Fx Studio
  • Home
  • Code
  • iOS & Swift
  • Combine
  • RxSwift
  • SwiftUI
  • Flutter & Dart
  • Tutorials
  • Art
  • Blog
Quick
Written by chuotfx on July 13, 2022

Quick trong 10 phút

iOS & Swift

Contents

  • Chuẩn bị
  • TDD (Test-Driven Development)
    • Tổng quan
    • Các bước để thực hiện TDD
    • Mô hình
  • BDD (Behavior Driven Development)
    • Tổng quan
    • Các bước để thực hiện BDD
    • Mô hình
  • Quick là gì?
  • Cài đặt thư viện
  • Ví dụ đơn giản
  • Vòng đời của Test Class
  • Các cú pháp cơ bản
  • Lưu ý khi sử dụng
  • BeforeEach & AfterEach
  • BeforeSuite & AfterSuite
    • Cách thức sử dụng
    • Một số lưu ý khi sử dụng beforeSuite và afterSuite:
  • Tạm kết

Chào mừng bạn đến với Fx Studio. UnitTest hay Testing trong iOS là một chủ đề khá thú vị. Chúng ta đã có cơ hội tìm hiểu cơ bản Testing là gì? rồi. Và chủ đề bài viết lần này sẽ là Quick. Nó có vai trò gì và sử dụng như thế nào trong UnitTest, thì ta sẽ tiếp tục tìm hiểu trong bài viết này nhóe!.

Nếu mọi việc đã ổn rồi, thì …

Bắt đầu thôi!

Chuẩn bị

Về mặt kiến thức, bạn cần hiểu qua các thuật ngữ cơ bản đầu tiền của iOS Testing trước nhóe. Nếu bạn chưa biết nó là gì, bạn có thể tham khảo bài viết sau:

  • Hello Testing iOS
  • UnitTest with Quick & Nimble
  • API Testing (UnitTest) with OHHTTPStubs

Về mặt công cụ, bạn chỉ cần có Xcode là xong nhóe. Bạn không cần quan tâm tới version Xcode, hay iOS … hầu như bạn sẽ sử dụng với các phiên bản mới nhất rồi.

Vì đã có một bài viết về cách viết UnitTest với Quick & Nimble rồi. Do đó, bài viết này chỉ tập trung những gì mà Quick có và cách bạn sử dụng thư viện mà thôi.

TDD (Test-Driven Development)

Tổng quan

Phát triển hướng kiểm thử TDD (Test-Driven Development) là một phương pháp tiếp cận cải tiến để phát triển phần mềm. Trong đó kết hợp phương pháp:

  • Phát triển kiểm thử trước (Test First Development)
  • Điều chỉnh lại mã nguồn (Refactoring).

Mục tiêu quan trọng nhất của TDD là hãy nghĩ về thiết kế của bạn trước khi viết mã nguồn cho chức năng.

Một quan điểm khác, lại cho rằng TDD là một kỹ thuật lập trình. Nhưng nhìn chung, mục tiêu của TDD là viết mã nguồn sáng sủa, rõ ràng và có thể chạy được.

Các bước để thực hiện TDD

  • Bước 1: Viết 1 test cho hàm mới. Đảm bảo rằng test sẽ fail.
  • Bước 2: Chuyển qua viết code sơ khai nhất cho hàm đó để test có thể pass.
  • Bước 3: Tối ưu hóa đoạn code của hàm vừa viết sao cho đảm bảo test vẫn pass và tối ưu nhất cho việc lập trình kế tiếp
  • Bước 4: Lặp lại cho các hàm khác từ bước 1

Mô hình

Quick TDD

(Xem hình tự hiểu nhóe. Ahihi)

BDD (Behavior Driven Development)

Tổng quan

BDD (Behavior Driven Development) là một quá trình phát triển phần mềm dựa trên phương pháp Agile (phát triển phần mềm linh hoạt). BDD là sự mở rộng của TDD (Test Driven Development).

Thay vì tập trung vào phát triển phần mềm theo hướng kiểm thử, BDD tập trung vào phát triển phần mềm theo hướng hành vi.

Dựa vào Requirement các kịch bản test (Scenarios) sẽ được viết trước dưới dạng ngôn ngữ tự nhiên và dễ hiểu nhất sau đó mới thực hiện cài đặt source code đễ pass qua tất cả các stories đó.

Các bước để thực hiện BDD

BDD được viết dưới dạng plain text language gọi là Gherkin. Cú pháp Gherkin chia thành 3 thành phần chính là:

  • feature
  • scenario
  • step.

Mỗi file gồm một Feature

  • Mỗi Feature gồm nhiều Scenario, bắt đầu bằng từ khóa “Feature:”. Mỗi Feature là 1 chức năng.
  • Mỗi Scenario gồm nhiều step, bắt đầu bằng từ khóa “Scenario:”. Mỗi Scenario là một testcase.
  • Mỗi step sẽ bắt đầu bằng các keyword như: Given, When, Then, But hoặc And. Trong đó:
    • “Given”: Mô tả ngữ cảnh ban đầu của hệ thống
    • “When”: Mô tả hành vi
    • “Then”: Mô tả kết quả
    • “And”, “But”: Kết hợp nhiều step giống nhau

Mô hình

Quick BDD

(Xem hình tự hiểu nhóe. Ahihi)

Quick là gì?

Quick là một khuôn khổ phát triển dựa trên hành vi (BDD) được thiết kế cho Swift & Objective-C và được xây dựng trên XCTest, cung cấp một phương pháp thuận tiện để soạn một bài kiểm tra đơn vị.

Nó sử dụng 1 hàm duy nhất spec() để xác định toàn bộ một bộ test. Trong spec() bao gồm nhiều phần:

  •  describe
  •  context
  •  it.

Quick sử dụng một cú pháp đặc biệt để xác định các testcase và các nhóm testcase nhằm phục vụ 2 mục đích:

  • Rõ nghĩa các mục đích của test bằng việc viết các mô tả cho từng testcase hay các nhóm testcase

  • Đơn giản hoá các mã kiểm tra trong bước sắp xếp các testcase của bạn

Cài đặt thư viện

Chúng ta sẽ bắt đầu việc cài đặt thư viện trước nhóe. Vì bạn có thể vài đường Google để biết chúng nó là gì rồi. Và chúng ta sẽ không quan tâm quá nhiều về mặt lý thuyết dài dòng kia.

Để cài đặt Quick & Nimble, mình sử dụng CocoaPods. Cách này cũng khá phổ thông và nếu bạn chưa biết cách sử dụng CocoaPod thì có thể đọc vài viết này nhóe! (theo 2 cách)

  • Cài đặt CocoaPods
  • Sử dụng Bundle cho iOS Project

Tiếp theo, bạn cập nhật lại PodFile để thêm các pod cho Quick & Nimble. Xem đoạn code ở Podfile như sau nhóe!

# Podfile
use_frameworks!
target "MyApp" do
  # Normal libraries
  abstract_target 'Tests' do
    inherit! :search_paths
    target "MyAppTests"
    target "MyAppUITests"
    pod 'Quick'
    pod 'Nimble'
  end
end

Các bạn nhớ để Quick & Nimble ở trong target Tests nha. Cụ thể ở đây là “FinalProjectTests”. Nếu bỏ nhầm chổ khác, thì lúc import nó ở file test sẽ không nhận đâu.

Ví dụ đơn giản

Chúng ta cùng nhau xem đoạn code ví dụ cho việc sử dụng Quick để thực hiện các testcase nhóe.

import Quick
import Nimble

@testable import QuickDemo

final class MoviesViewModelTest: QuickSpec {

    override func spec() {

        var viewModel: MoviesViewModel!

        describe("Movies view model") {

            context("When movie is not nil") {

                beforeEach {
                    viewModel = MoviesViewModel()
                    let movies = MoviesDataHelper.getMovies()
                    viewModel.movies = movies
                }

                it("Number of item should be return 8 movies") {
                    expect(viewModel.numberOfItems(inSection: 0)) == 8
                }

                it("Movies cell view model should be an instance of MoviesCellViewModel") {
                    let indexPath = IndexPath(row: 0, section: 0)
                    expect { try viewModel.viewModelForItem(at: indexPath) }
                        .to(beAnInstanceOf(MoviesCellViewModel.self))
                }

                it("Error should be index is out of bounds") {
                    let indexPath = IndexPath(row: 100, section: 0)
                    expect { try viewModel.viewModelForItem(at: indexPath) }
                        .to(throwError())
                }
            }

            afterEach {
                viewModel = nil
            }
        }
    }
}

Trong đó:

  • Chúng ta có 1 hàm spec() để chứa các testcase
  • Việc phân nhóm các testcase dựa theo việc chia phân cấp với describe & context
  • Mỗi testcase được quy định bởi it

Nội dung mỗi testcase là việc so sánh kết quả với mong đợi. Phần này, chúng ta đã tìm hiểu trong bài Nimble trong 10 phút rồi nhóe!

Vòng đời của Test Class

Quick

(Hình vẽ hơi xấu, bạn thông cảm nhóe!)

Qua hình, ta sẽ thấy các testcase sẽ được chạy theo việc phân cấp từ Describe và Context. Cho tới khi nào hết testcase thì Test Class sẽ kết thúc. EZ Game!

Các cú pháp cơ bản

describe:

  • Là một gói các testcase có cùng một chức năng. Mô tả chính xác phần mà bạn đang kiểm tra.

context:

  • Là một gói các testcase có cùng một chức năng. Mô tả chính xác phần mà bạn đang kiểm tra.

it:

  • Mô tả kết quả dự kiến của phần mà bạn muốn kiểm tra. Đây là trường hợp kiểm tra chính xác và được coi là một testcase.

Theo như định nghĩa trên, đối tượng phải được khai báo trong context. Trạng thái của nó phải được sửa đổi trong context hoặc it và mong muốn phải đúng với kết quả của it.

Và cần nhớ cấu trúc được sử dụng từ trên xuống , được khai báo trong phần describe và được chia sẻ giữa các contexts.

Lưu ý khi sử dụng

  • Từ khoá context là một từ đồng nghĩa với mô tả. Tuy nhiên, nếu sử dụng thích hợp thì sẽ làm cho spec() của bạn dễ hiểu hơn.
  • Testcase sử dụng it:

    • Được định nghĩa với chức năng it, sử dụng thể khẳng định để chứng minh đoạn mã nên trả về như thế nào?

    • it có hai tham số: mô tả của testcase và một closure. Mô tả không giới hạn độ dài và được sử dụng tất cả mọi ký tự.

  • Nhóm testcase sử dụng describe và context:

    • Nhóm testcase là các nhóm hợp lý của các testcase. Các nhóm testcase được sử dụng chung setup() và teardown().
  • Mô tả các lớp và các phương thức sử dụng describe:
    • Để kiểm tra một phương thức hoạt động, một vài testcase it được nhóm lại với nhau bằng cách thức sử dụng chức năng describe. Nhóm các testcase tương tự lại với nhau làm cho spec() dễ đọc hơn.

Một tính năng khác mà hay được sử dụng khi dùng Quick là: beforeEach và afterEach

BeforeEach & AfterEach

Cách thức sử dụng chúng như sau:

  • Sử dụng giống hai hàm setup() và teardown() ở XCTest
  • Được thực hiện ở đầu và cuối mỗi trường hợp kiểm tra it
  • Có thể được định nghĩa bên trong bất kỳ describe hay context
  • Nếu chúng có mặt trong cả context và describe thì beforeEach sẽ chạy đầu tiên ở describe rồi mới chạy trong context, còn afterEach sẽ ngược lại, chạy ở context trước rồi mới tới describe
  • Bất kỳ biến nào được gán giá trị trong beforeEach có thể sử dụng bên trong thân của it

Ví dụ code như sau:

import Quick

class Spec: QuickSpec {

  override func spec() {

    describe("beforeEach and afterEach behaviour") {

      beforeEach {
        print("⭐️ top before each")
      }

      context("some context") {

        beforeEach {
          print("👉 context before each")
        }

        it("example 1") { print("😊 example 1") }

        it("example 2") { print("😊 example 2") }

        it("example 3") { print("😊 example 3") }

        afterEach {
          print("👉 context after each")
        }
      }

      context("another context") {

        beforeEach {
          print("🍎 context before each")
        }

        it("example 1") { print("😜 example 1") }

        it("example 2") { print("😜 example 2") }

        afterEach {
          print("🍎 context after each")
        }
      }

      afterEach {
        print("⭐️ top after each")
      }
    }
  }
}

Ta có kết quả chạy test như sau:

behaviour - some context - example 1
⭐️ top before each
👉 context before each
😊 example 1
👉 context after each
⭐️ top after each

behaviour - some context - example 2
⭐️ top before each
👉 context before each
😊 example 2
👉 context after each
⭐️ top after each

behaviour - some context - example 3
⭐️ top before each
👉 context before each
😊 example 3
👉 context after each
⭐️ top after each

behaviour - other context - example 1
⭐️ top before each
🍎 context before each
😜 example 1
🍎 context after each
⭐️ top after each

behaviour - other context - example 2
⭐️ top before each
🍎 context before each
😜 example 2
🍎 context after each
⭐️ top after each

BeforeSuite & AfterSuite

Một số thiết lập thử nghiệm cần được thực hiện trước khi bất kỳ các trường hợp kiểm tra nào được chạy. Trong trường hợp đó thì ta cần sử dụng beforeSuite và afterSuite.

Cách thức sử dụng

  • BeforeSuite: Xác định một closure sẽ được chạy trước tiên bất kỳ các testcase nào và chạy một lần duy nhất trong một bộ thử nghiệm. Bạn có thể định nghĩa nhiều BeforeSuite nhưng không có gì đảm bảo về thứ tự mà chúng đang chạy.

  • AfterSuite: Xác định một closure sẽ được chạy sau cùng bất kỳ các testcase nào và chạy một lần duy nhất trong một bộ thử nghiệm. Bạn có thể định nghĩa nhiều AfterSuite nhưng không có gì đảm bảo về thứ tự mà chúng đang chạy.

Chúng ta xem qua ví dụ code tiếp nhóe!

import Quick

class Spec: QuickSpec {
  override func spec() {
    beforeSuite {
      print("☕️ before suite")
    }

    describe("beforeEach and afterEach behaviour") {
      beforeEach {
        print("⭐️ top before each")
      }

      context("some context") {
        beforeEach {
          print("👉 context before each")
        }

        it("example 1") { print("😊 example 1") }

        it("example 2") { print("😊 example 2") }

        afterEach {
          print("👉 context after each")
        }
      }

      afterEach {
        print("⭐️ top after each")
      }
    }

    afterSuite {
      print("🗑 after suite")
    }
  }
}

Ta có kết quả chạy test như sau:

☕️ before suite

behaviour - some context - example 1
⭐️ top before each
👉 context before each
😊 example 1
👉 context after each
⭐️ top after each

behaviour - other context - example 2
⭐️ top before each
🍎 context before each
😜 example 2
🍎 context after each
⭐️ top after each

🗑 after suite

 

Một số lưu ý khi sử dụng beforeSuite và afterSuite:

  • Trong một class test chỉ nên định nghĩa beforeSuite và afterSuite một lần duy nhất để đảm bảo về thứ tự chạy của mỗi closure trong class đó.

  • Trong một dự án, bạn có thể chỉ định càng nhiều càng tốt các beforeSuite và afterSuite như bạn muốn. Tất cả các closure beforeSuite sẽ được thực hiện trước khi bất kì các class test nào được chạy, và tất cả các closure afterSuite sẽ được thực hiện khi tất cả các testcase được kiểm tra hết.

  • Khi chạy một class test, thì closure beforeSuite sẽ được thực hiện nhưng closure afterSuite sẽ không được thực hiện trừ khi test toàn bộ project.

Tạm kết

  • Tìm hiểu về các mô hình TDD & BDD trong việc áp dụng UnitTest
  • Tìm hiểu về thư viện Quick, cách cài đặt
  • Các cú pháp cơ bản sử dụng Quick cho các testcase
  • Sử dụng các before & after trong việc thực thi 1 hay nhóm testcase

 

Okay! Tới đây, mình xin kết thúc bài viết về Quick trong UnitTest . Nếu có gì thắc mắc hay góp ý cho mình thì bạn có thể để lại bình luận hoặc gởi email theo trang Contact.

  • Bài viết tiếp theo: (đang cập nhật)

Cảm ơn bạn đã đọc bài viết này!

FacebookTweetPinYummlyLinkedInPrintEmailShares7

Related Posts:

  • Opaque Type trong 10 phút - Swift
    Opaque Type trong 10 phút - Swift
  • UnitTest with Quick & Nimble
    UnitTest with Quick & Nimble
  • Generics trong 10 phút - Swift
    Generics trong 10 phút - Swift
  • Convenience Initializer trong 10 phút
    Convenience Initializer trong 10 phút
Tags: iOS, testing, unittest
Written by chuotfx

Hãy ngồi xuống, uống miếng bánh và ăn miếng trà. Chúng ta cùng nhau đàm đạo về đời, về code nhóe!

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

Donate – Buy me a coffee!

Fan page

Fx Studio

Tags

Actor Advanced Swift api AppDistribution Asynchronous autolayout basic ios tutorial blog callback ci/cd closure collectionview combine concurrency CoreData Core Location crashlytics darkmode dart dart basic dart tour Declarative decoding delegate deploy fabric fastlane firebase flavor flutter GCD iOS mapview MVVM optional protocol rxswift Swift Swift 5.5 SwiftUI SwiftUI Notes tableview testing TravisCI unittest

Recent Posts

  • Raw String trong 10 phút
  • Dispatch Semaphore trong 10 phút
  • Tổng kết năm 2022
  • KeyPath trong 10 phút – Swift
  • Make color App Flutter
  • Ứng dụng Flutter đầu tiên
  • Cài đặt Flutter SDK & Hello world
  • Coding Conventions – người hùng hay kẻ tội đồ?
  • Giới thiệu về Flutter
  • Tìm hiểu về ngôn ngữ lập trình Dart

You may also like:

  • Property Wrapper trong 10 phút
    Property Wrapper trong 10 phút
  • Keychain trong 10 phút - iOS
    Keychain trong 10 phút - iOS
  • Generics trong 10 phút - Swift
    Generics trong 10 phút - Swift
  • Task & Task Group trong 10 phút - Swift 5.5
    Task & Task Group trong 10 phút - Swift 5.5
  • File Manager trong 10 phút - Swift
    File Manager trong 10 phút - Swift

Archives

  • February 2023 (1)
  • January 2023 (2)
  • November 2022 (2)
  • October 2022 (1)
  • September 2022 (5)
  • August 2022 (6)
  • July 2022 (7)
  • June 2022 (8)
  • May 2022 (5)
  • April 2022 (1)
  • March 2022 (3)
  • February 2022 (5)
  • January 2022 (4)
  • December 2021 (6)
  • November 2021 (8)
  • October 2021 (8)
  • September 2021 (8)
  • August 2021 (8)
  • July 2021 (9)
  • June 2021 (8)
  • May 2021 (7)
  • April 2021 (11)
  • March 2021 (12)
  • February 2021 (3)
  • January 2021 (3)
  • December 2020 (3)
  • November 2020 (9)
  • October 2020 (7)
  • September 2020 (17)
  • August 2020 (1)
  • July 2020 (3)
  • June 2020 (1)
  • May 2020 (2)
  • April 2020 (3)
  • March 2020 (20)
  • February 2020 (5)
  • January 2020 (2)
  • December 2019 (12)
  • November 2019 (12)
  • October 2019 (19)
  • September 2019 (17)
  • August 2019 (10)

About me

Education, Mini Game, Digital Art & Life of coders
Contacts:
contacts@fxstudio.dev

Fx Studio

  • Home
  • About me
  • Contact us
  • Mail
  • Privacy Policy
  • Donate
  • Sitemap

Categories

  • Art (1)
  • Blog (22)
  • Code (4)
  • Combine (22)
  • Flutter & Dart (24)
  • iOS & Swift (86)
  • RxSwift (37)
  • SwiftUI (76)
  • Tutorials (70)

Newsletter

Stay up to date with our latest news and posts.
Loading

    Copyright © 2023 Fx Studio - All rights reserved.

    Share this ArticleLike this article? Email it to a friend!

    Email sent!