[Legacy] Dùng Swiftlint trong viết test script cho project iOS

Posted on May 24th, 2019

Một team quy tụ những coder với phong cách cá nhân khác nhau rất có thể xảy ra mâu thuẫn. Nhẹ thì nhìn nhau bằng ánh mắt hình viên đạn, nặng thì cãi cọ solo skill để rồi qua hôm sau lên mặt báo Thanh niên hỗn chiến vì đặt tên biến. Cho nên để dễ dàng hơn trong việc cộng tác hướng tới mục tiêu chung là bảo tồn chén cơm manh áo, có một nhóm các công cụ gọi chung là linter, thực hiện công việc linting (linh tinh 🤪😜) giúp đưa ra một guideline để các thành viên trong team nương theo đó mà code, phần nào hạn chế xung đột giữa những phong cách khác nhau.

Tuỳ vào môi trường phát triển hay ngôn ngữ lập trình được sử dụng mà sẽ có cụ thể từng linter, trong đó, Swiftlint là một cái tên được nhắc tới khi code Swift. Swiftlint được maintained bởi Realm với một Github repository được contrubite khá là thường xuyên. Cũng tương tự như các anh em khác trong dòng họ linter, nó hoạt động dựa trên những rule được khai báo từ trước để báo warning / error trên mỗi lần build project khi phát hiện trong source code có violation so với những rule đã định trước đó.

A tool to enforce Swift style and conventions, loosely based on GitHub's Swift Style Guide.

Cài đặt

Có vài cách để cài đặt Swiftlint, trong đó đơn giản nhất là thông qua Homebrew trên macOS với command:

$ brew install swiftlint
==> Downloading https://homebrew.bintray.com/bottles/swiftlint-0.32.0.mojave.bottle.tar.gz
Already downloaded: /Library/Caches/Homebrew/downloads/4f9559ebeb4944bcaee86154b8822d5522813e7de93da3f2e947292b934176c6--swiftlint-0.32.0.mojave.bottle.tar.gz
==> Pouring swiftlint-0.32.0.mojave.bottle.tar.gz
🍺  /usr/local/Cellar/swiftlint/0.32.0: 6 files, 7.5MB

Kiểm tra cài đặt:

$ which swiftlint
/usr/local/bin/swiftlint

Sử dụng

Sau khi cài đặt với cách trên, chúng ta có thể sử dụng ngay Swiftlint các command của nó trong Terminal. Dùng help để list ra các command khả dụng :

$ swiftlint help
Available commands:

   analyze         [Experimental] Run analysis rules
   autocorrect     Automatically correct warnings and errors
   generate-docs   Generates markdown documentation for all rules
   help            Display general or command-specific help
   lint            Print lint warnings and errors (default command)
   rules           Display the list of rules and their identifiers
   version         Display the current version of SwiftLint

Có thể thấy trong list các command trên, thì lint là command mặc định mà swiftlint sẽ sử dụng. Do đó, chúng ta có thể kiểm tra nhanh bằng cách di chuyển vào thư mục project và run command swiftlint.

$ cd Desktop/CodeCoverageDemo
$ swiftlint
Linting Swift files at paths
Linting 'ModelController.swift' (1/6)
Linting 'DataViewController.swift' (2/6)
Linting 'XCCov_DemoTests.swift' (3/6)
Linting 'AppDelegate.swift' (4/6)
Linting 'RootViewController.swift' (5/6)
Linting 'XCCov_DemoUITests.swift' (6/6)
~/Desktop/CodeCoverageDemo/XCCov-Demo/DataViewController.swift:34:1: warning: Trailing Newline Violation: Files should have a single trailing newline. (trailing_newline)
~/Desktop/CodeCoverageDemo/XCCov-Demo/DataViewController.swift:16:1: warning: Vertical Whitespace Violation: Limit vertical whitespace to a single empty line. Currently 2. (vertical_whitespace)
~/Desktop/CodeCoverageDemo/XCCov-Demo/DataViewController.swift:32:1: warning: Vertical Whitespace Violation: Limit vertical whitespace to a single empty line. Currently 2. (vertical_whitespace)
......
Done linting! Found 65 violations, 13 serious in 6 files.

Trong ví dụ trên, thư mục project là ~/Desktop/CodeCoverageDemo. Sau khi swiftlint chạy xong, nó sẽ báo lỗi dựa theo bộ rule mặc định mà đã được cộng đồng developer Swift định nghĩa và thống nhất tại https://github.com/realm/SwiftLint/blob/master/Rules.md. Ví dụ một rule sẽ có cấu trúc như sau:

swiftlint rule trailing whitespace

Điểm đáng lưu ý là đối với những rule có hỗ trợ tự động điều chỉnh, Supports autocorrection: Yes, thì chúng ta có thể sử dụng command autocorrect để Swiftlint điều chỉnh code sao cho trở nên hợp lệ với rule này.

$ swiftlint autocorrect
Correcting Swift files at paths
Correcting 'RootViewController.swift' (1/6)
Correcting 'AppDelegate.swift' (2/6)
Correcting 'ModelController.swift' (3/6)
Correcting 'XCCov_DemoTests.swift' (4/6)
Correcting 'DataViewController.swift' (5/6)
Correcting 'XCCov_DemoUITests.swift' (6/6)
~/Desktop/CodeCoverageDemo/XCCov-DemoTests/XCCov_DemoTests.swift:13:1 Corrected Trailing Whitespace
~/Desktop/CodeCoverageDemo/XCCov-DemoTests/XCCov_DemoTests.swift:18:1 Corrected Trailing Whitespace
~/Desktop/CodeCoverageDemo/XCCov-DemoTests/XCCov_DemoTests.swift:23:1 Corrected Trailing Whitespace
~/Desktop/CodeCoverageDemo/XCCov-DemoTests/XCCov_DemoTests.swift:28:1 Corrected Trailing Whitespace
~/Desktop/CodeCoverageDemo/XCCov-DemoTests/XCCov_DemoTests.swift:35:1 Corrected Trailing Whitespace
~/Desktop/CodeCoverageDemo/XCCov-DemoUITests/XCCov_DemoUITests.swift:12:1 Corrected Trailing Whitespace
~/Desktop/CodeCoverageDemo/XCCov-DemoUITests/XCCov_DemoUITests.swift:15:1 Corrected Trailing Whitespace
~/Desktop/CodeCoverageDemo/XCCov-DemoUITests/XCCov_DemoUITests.swift:17:1 Corrected Trailing Whitespace
~/Desktop/CodeCoverageDemo/XCCov-DemoUITests/XCCov_DemoUITests.swift:25:1 Corrected Trailing Whitespace
~/Desktop/CodeCoverageDemo/XCCov-DemoUITests/XCCov_DemoUITests.swift:30:1 Corrected Trailing Whitespace
~/Desktop/CodeCoverageDemo/XCCov-DemoUITests/XCCov_DemoUITests.swift:35:1 Corrected Trailing Whitespace
~/Desktop/CodeCoverageDemo/XCCov-Demo/ModelController.swift:56:1 Corrected Trailing Whitespace
~/Desktop/CodeCoverageDemo/XCCov-Demo/ModelController.swift:66:1 Corrected Trailing Whitespace
Done correcting 6 files!

Swiftlint configuration file

Đến đây thì chúng ta vẫn đang sử dụng những config mặc định của swiftlint. Tuy nhiên nó có thể được configure cho phù hợp với tình hình dự án bằng cách tạo mới file .swiftlint.yml với nội dung như ví dụ sau:

$ touch .swiftlint.yml
$ nano .swiftlint.yml
disabled_rules: # các rule loại bỏ
  - trailing_whitespace
  - identifier_name
  - function_body_length
  - type_name
  - cyclomatic_complexity
  - force_cast
  - line_length
opt_in_rules: # các rule được thêm vào
  - control_statement
  - empty_count
  - trailing_newline
  - colon
  - comma
excluded: # đường dẫn bỏ qua việc kiểm tra
  - Pods
#included:
#  - XCCov-DemoTests

# hiển thị warning khi sử dụng force casting
force_cast: warning
force_try:
  severity: warning

# giới hạn
function_body_length:
  warning: 50
  error: 60
line_length: 120

reporter: "xcode"

Khi đó, nếu chạy lại command swiftlint nó sẽ tự detect file configuration và thực thi theo những config đó.

$ swiftlint
Loading configuration from '.swiftlint.yml'
Found a configuration for 'line_length' rule, but it is disabled on 'disabled_rules'.
Found a configuration for 'function_body_length' rule, but it is disabled on 'disabled_rules'.
Found a configuration for 'force_cast' rule, but it is disabled on 'disabled_rules'.
Linting Swift files at paths
Linting 'XCCov_DemoTests.swift' (1/1)
Done linting! Found 0 violations, 0 serious in 1 file.

Tích hợp vào Xcode

Thay vì phải gõ command ở Terminal khá là mất thời gian, chúng ta có thể tích hợp Swiftlint vào Xcode scheme bằng cách add Run Script Phase để tự động chạy Swiftlint trong mỗi lần build.

xcode swiftlint add run script

Kết

Như vậy, dựa trên kỹ thuật phân tích code tĩnh, static code analysis (nói một cách ngắn gọn là kiểm tra code mà không cần phải thực thi), linter nói chung và Swiftlint nói riêng giúp team thống nhất được những quy tắc nhất định trong coding, đồng thời tránh những lỗi phát sinh không cần thiết trong quá trình làm việc nhóm. Điều này tỏ ra đặc biệt quan trọng đối với những project có số lượng coder tham gia tương đối nhiều cùng với đó là sự đa dạng về phong cách cũng như kinh nghiệm làm việc.