Help us understand the problem. What is going on with this article?

Swift2.0で追加された@testableはprivateにはアクセスできない

More than 5 years have passed since last update.

Swift2.0でUnit Testを書く際に@testableというattributeが追加されました。
この@testableを使用する際の注意事項です。

まずはアクセス制御について確認しましょう。以前書いたものから引っ張ってきました。

アクセス制御

Swiftは モジュールソースファイル をアクセス制御の単位としています。

アクセスレベル 用途
public どこからでもアクセス可能 どこからでもアクセス可能なのでframeworkのAPIを定義する場合はこれを使う
internal デフォルトのアクセスレベル 自身のモジュールと同じモジュールのソースファイル内であればアクセス可能。何も指定しない場合はこれが指定される。
private 最も厳しいアクセスレベル モジュール内の同じソースファイルでなければアクセスできない。外部に隠蔽しておきたいものはこれを指定。

@testableの書き方

@testableimportと一緒に記載します。以下はProductKitというEmbedded Frameworkを作成し、そのUTを記述した際のものです。

ProductKitTests.swift
import XCTest
@testable import ProductKit

class ProductKitTests: XCTestCase {

    override func setUp() {
        super.setUp()
    }

    override func tearDown() {
        super.tearDown()
    }

    func testExample() {
        let something = Something(publicName: "public", internalName: "internal")
        something.publicHello(something.publicName)
        something.internalHello(something.internalName)
    }
}

2行目のimportの前に@testableを記述しています。internalなメソッドやプロパティに対してはこれでアクセス可能になります。

注意点

注意点としては、@testableをつけてもアクセス可能なのはinternalまでで、privateな関数、メソッド、プロパティにはアクセスできません。

よく考えれば、外部モジュールにさえしておけばinternalで十分隠蔽されている状態になります。モジュールが分かれていればinternalなプロパティやメソッドにはアクセスできないので。

いままで外部モジュールで作成したクラス内の、内部でしか使用しないメソッドなどはprivateにしていましたが、モジュールが分かれていれば参照不可能になるのでinternalで十分なのかもしれません。というか、そうしないとテスト不可能になります。

ただし同一モジュール内ではinternalなプロパティやメソッドにはアクセスできてしまうわけで、隠蔽したいからとprivateをつけてしまうと、外部モジュールであるテストターゲット内で参照不可能になってしまいます。

なんだか手が届かないところがかゆい感じです。

mercari
フリマアプリ「メルカリ」を、グローバルで開発しています。
https://tech.mercari.com/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away