私はクラスをテストしようとしていますが、何をテストするかについて少し混乱しています。これが私が単体テストしたいクラスです:
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
のすべての操作(+、-、*、/など)をテストする価値はありますか?
プライベートメソッドをテストする価値はありますか?
@testable
を使用してSwiftでプライベートメソッドをテストすることはできません。テストできるのは、internal
またはpublic
のいずれかのマークが付いたメソッドのみです。
注:@testableは、「内部」関数にのみアクセスを提供します。 「プライベート」宣言は、@ testableを使用している場合でも、ファイルの外からは見えません。
続きを読む こちら
定義によるユニットテストはブラックボックステストです。つまり、テストするユニットの内部については気にしません。主に、ユニットテストで指定した入力に基づいて、ユニットの出力を確認します。
これで、出力により、いくつかのことをアサートできます。
すべての場合において、私たちはパブリックインターフェースのみに関心があります。これは、他の世界と通信するインターフェースだからです。
プライベートなものは、パブリックなものによって間接的に使用されるため、ユニットテストを持つ必要はありません。秘Theは、プライベートメンバーが完全にカバーされるようにパブリックメンバーを実行する十分なテストを作成することです。
また、覚えておくべき重要なことの1つは、単体テストでは実装ではなく単体仕様を検証する必要があるということです。実装の詳細を検証すると、単体テストコードとテスト済みコードの間に緊密なカップリングが追加されますが、これには大きな欠点があります。そのコードの単体テスト。
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())
}
}
これがハッキングであることを完全に理解しています。しかし、このトリックを知っていれば、将来ベーコンを節約できるかどうかはわかりません。このトリックを悪用しないでください。
このリンク が見つかりました。これはCristikと似たようなことを言っています。
基本的に、あなたは間違った質問をしているので、「プライベート」とマークされたクラス/関数をテストしようとするべきではありません。