Swift-单元测试专用变量和方法
我正在试着测试一门课,但我有点搞不清楚该测试什么。下面是我想进行单元测试的类:Swift-单元测试专用变量和方法,swift,unit-testing,Swift,Unit Testing,我正在试着测试一门课,但我有点搞不清楚该测试什么。下面是我想进行单元测试的类: class CalculatorBrain { private var accumulator = 0.0 func setOperand(operand: Double) { accumulator = operand } var result: Double { return accumulator } private var
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
}
}
}
class CalculatorBrain{
专用var累加器=0.0
func集合操作数(操作数:双精度){
累加器=操作数
}
var结果:双{
回流蓄能器
}
私有变量操作:字典=[
“=”:。等于,
“π”:.常数(M_π),
“e”:.常数(M_e),
“±”:.UnaryOperation({(op1:Double)->返回双精度-op1}),
"√" : .一元操作(sqrt),
“cos”:.一元操作(cos),
“+”:.BinaryOperation({(op1:Double,op2:Double)->Double返回op1+op2}),
"−:.BinaryOperation({(op1:Double,op2:Double)->返回op1-op2}中的Double),
“×”:.BinaryOperation({(op1:Double,op2:Double)->返回op1*op2}中的Double),
“÷”:.BinaryOperation({(op1:Double,op2:Double)->返回op1/op2}中的Double)
]
私有枚举操作{
案例常数(双)
案例一元运算((双)->双)
case二进制操作((双精度,双精度)->Double)
大小写相等
}
func性能操作(符号:字符串){
如果let操作=操作[符号]{
开关操作{
案例常数(let值):
累加器=值
一元运算(let函数):
累加器=功能(累加器)
case.BinaryOperation(let函数):
executePendingBinaryOperation()
pendingBinaryOperation=PendingBinaryOperationInfo(binaryOperation:函数,第一个操作数:累加器)
案例。等于:
executePendingBinaryOperation()
}
}
}
私有变量pendingBinaryOperation:PendingBinaryOperationInfo?
私有结构PendingBinaryOperationInfo{
var二进制操作:(双精度,双精度)->Double
var第一个操作数:双精度
}
私有func executePendingBinaryOperation(){
如果let pending=pendingBinaryOperation{
累加器=pending.binaryOperation(pending.FirstOperator,累加器)
pendingBinaryOperation=nil
}
}
}
对于上面的代码,什么是好的测试
是否值得测试字典operations
中的每个操作(+、-、*、/,等等)
值得测试私有方法吗?单元测试应该被视为黑盒测试,这意味着您不关心您测试的单元的内部。您主要感兴趣的是根据您在单元测试中给出的输入来查看单元输出是什么 现在,通过输出,我们可以断言以下几点:
- 方法的结果
- 作用于对象后的对象状态
- 与对象具有的依赖项的交互
以黑盒方式编写单元测试意味着您可以重构这些单元中的所有代码,而无需担心更改测试可能会在单元测试代码中引入错误。不可靠的单元测试有时比缺少测试更糟糕,因为给出误报的测试可能会隐藏实际错误您的代码中存在错误。您不能使用
@testable
在Swift中测试私有方法。您只能测试标记为internal
或public
的方法。正如文档所述:
注:@testable仅为“内部”功能提供访问权限;
“private”声明在其文件外不可见,即使在
使用@testable
阅读更多内容我发现这与克里斯蒂克的说法类似
基本上,您提出的问题是错误的,您不应该试图测试标记为“private”的类/函数。尽管我同意不测试
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 Diego's answer is clever but it is possible to go further.
- Go into your project editor and define a new Testing Configuration by duplicating the Debug configuration.
- Edit your scheme's Test action so that the build configuration is Testing.
- Now edit your test target's build settings to define an additional Active Compilation Conditions value for the Testing configuration,
"TESTING"
.
Now you can say #if TESTING
, as distinct from mere DEBUG
.
I use this, for example, to declare initializers that only a test can see.I think actually don’t need to test of private members.
But if you want to use to private
members(properties & methods) at UnitTest
, there is a way that use Protocol
.
Protocol PrivateTestable {
associatedtype PrivateTestCase
var privateTestCase: PrivateTestCase {get}
}
<代码>导入基础
公开课考试{
内部函数testInternal()->Int{
返回1
}
public func testPublic()->Int{
返回2
}
//我们不能测试这个!
private func testPrivate()->Int{
返回3
}
}
//由于#if DEBUG,无法随生产代码一起提供
//加上一句很好的评论:“为什么需要这样做Diego的回答很聪明,但可以更进一步
进入项目编辑器,通过复制调试配置定义新的测试配置
编辑方案的测试操作,以便生成配置正在测试
现在编辑测试目标的生成设置,为测试配置定义一个附加的活动编译条件值,“Testing”
现在,您可以说“如果测试”
,而不仅仅是“调试”
例如,我使用它来声明只有测试才能看到的初始值设定项。我认为实际上不需要测试私有成员。 但是如果你想使用
private