web-dev-qa-db-ja.com

Swift-プライベート変数とメソッドの単体テスト

私はクラスをテストしようとしていますが、何をテストするかについて少し混乱しています。これが私が単体テストしたいクラスです:

class CalculatorBrain {

    private var accumulator = 0.0

    func setOperand(operand: Double) {
        accumulator = operand
    }

    var result: Double {
        return accumulator
    }

    private var operations: Dictionary<String, Operation> = [
        "=" : .Equals,

        "π" : .Constant(M_PI),
        "e" : .Constant(M_E),

        "±" : .UnaryOperation({ (op1: Double) -> Double in return -op1 }),
        "√" : .UnaryOperation(sqrt ),
        "cos": .UnaryOperation(cos),

        "+" : .BinaryOperation({ (op1: Double, op2: Double) -> Double in return op1 + op2 }),
        "−" : .BinaryOperation({ (op1: Double, op2: Double) -> Double in return op1 - op2 }),
        "×" : .BinaryOperation({ (op1: Double, op2: Double) -> Double in return op1 * op2 }),
        "÷" : .BinaryOperation({ (op1: Double, op2: Double) -> Double in return op1 / op2 })
    ]

    private enum Operation {
        case Constant(Double)
        case UnaryOperation((Double) -> Double)
        case BinaryOperation((Double, Double) -> Double)
        case Equals
    }

    func performOperation(symbol: String) {
        if let operation = operations[symbol] {
            switch operation {
            case .Constant(let value):
                accumulator = value
            case .UnaryOperation(let function):
                accumulator = function(accumulator)
            case .BinaryOperation(let function):
                executePendingBinaryOperation()
                pendingBinaryOperation = PendingBinaryOperationInfo(binaryOperation: function, firstOperand: accumulator)
            case .Equals:
                executePendingBinaryOperation()
            }
        }
    }

    private var pendingBinaryOperation: PendingBinaryOperationInfo?

    private struct PendingBinaryOperationInfo {
        var binaryOperation: (Double, Double) -> Double
        var firstOperand: Double
    }

    private func executePendingBinaryOperation() {
        if let pending = pendingBinaryOperation {
            accumulator = pending.binaryOperation(pending.firstOperand, accumulator)
            pendingBinaryOperation = nil
        }
    }
}

上記のコードの場合、良いテストになるでしょう。

辞書operationsのすべての操作(+、-、*、/など)をテストする価値はありますか?

プライベートメソッドをテストする価値はありますか?

36
breaktop

@testableを使用してSwiftでプライベートメソッドをテストすることはできません。テストできるのは、internalまたはpublicのいずれかのマークが付いたメソッドのみです。

注:@testableは、「内部」関数にのみアクセスを提供します。 「プライベート」宣言は、@ testableを使用している場合でも、ファイルの外からは見えません。

続きを読む こちら

29
Daniel Galasko

定義によるユニットテストはブラックボックステストです。つまり、テストするユニットの内部については気にしません。主に、ユニットテストで指定した入力に基づいて、ユニットの出力を確認します。

これで、出力により、いくつかのことをアサートできます。

  • メソッドの結果
  • オブジェクトに作用した後のオブジェクトの状態、
  • オブジェクトが持つ依存関係との相互作用

すべての場合において、私たちはパブリックインターフェースのみに関心があります。これは、他の世界と通信するインターフェースだからです。

プライベートなものは、パブリックなものによって間接的に使用されるため、ユニットテストを持つ必要はありません。秘Theは、プライベートメンバーが完全にカバーされるようにパブリックメンバーを実行する十分なテストを作成することです。

また、覚えておくべき重要なことの1つは、単体テストでは実装ではなく単体仕様を検証する必要があるということです。実装の詳細を検証すると、単体テストコードとテスト済みコードの間に緊密なカップリングが追加されますが、これには大きな欠点があります。そのコードの単体テスト。

24
Cristik

privateをテストしないことに同意しますが、パブリックインターフェイスのみをテストすることを好みますが、非表示のクラス(複雑なステートマシンなど)内で何かをテストする必要がある場合があります。これらの場合にできることは次のとおりです。

import Foundation

public class Test {

    internal func testInternal() -> Int {
        return 1
    }

    public func testPublic() -> Int {
        return 2
    }

    // we can't test this!        
    private func testPrivate() -> Int {
        return 3
    }
}

// won't ship with production code thanks to #if DEBUG
// add a good comment with "WHY this is needed ????"
#if DEBUG
extension Test {
    public func exposePrivate() -> Int {
        return self.testPrivate()
    }
}
#endif

次に、これを行うことができます:

import XCTest
@testable import TestTests

class TestTestsTests: XCTestCase {

    func testExample() {
        let sut = Test()

        XCTAssertEqual(1, sut.testInternal())
    }

    func testPrivateExample() {
        let sut = Test()

        XCTAssertEqual(3, sut.exposePrivate())
    }
}

これがハッキングであることを完全に理解しています。しかし、このトリックを知っていれば、将来ベーコンを節約できるかどうかはわかりません。このトリックを悪用しないでください。

11
Diego Freniche

このリンク が見つかりました。これはCristikと似たようなことを言っています。

基本的に、あなたは間違った質問をしているので、「プライベート」とマークされたクラス/関数をテストしようとするべきではありません。

0
Joey Zhou