在 XCTAssertEqual 中使用 Foundation Decimal 类型
Posted
技术标签:
【中文标题】在 XCTAssertEqual 中使用 Foundation Decimal 类型【英文标题】:Using Foundation Decimal type in XCTAssertEqual 【发布时间】:2020-03-14 10:16:22 【问题描述】:我正在构建一些类和代码来存储和执行货币值的算术运算。我最初使用的是 Doubles,但由于算术错误而转换为 Decimal。
我正在尝试找到针对使用 Decimal 类型的函数运行单元测试的最佳方法。
考虑 position.totalCost
是 Decimal 类型。
XCTAssertEqual(position.totalCost, 3571.6, accuracy: 0.01)
此代码无法编译,因为 Decimal 不符合 FloatingPoint。 XCTAssertEqual 要求参数为 Doubles 或 Floats。
我通过以下方式解决了这个问题:
XCTAssertTrue(position.totalCost == 3571.6)
哪个有效,但如果在单元测试期间出现错误,我会收到一条模糊的消息:
XCTAssertTrue failed
而不是更有用的XCTAssertEqual failed: ("2.0") is not equal to ("1.0")
所以使用 XCTAssertEqual 是理想的。
可能的选择(作为新手,不知道哪个更好或可行)
编写我的 Position 类以将所有属性存储为 Decimal,但使用计算属性获取并将它们设置为 Doubles。
编写一个接受小数的自定义断言。这可能是最“正确”的路径,因为到目前为止我在使用小数时遇到的唯一问题是 XCT 断言不能接受它们。
编写一个愚蠢的十进制扩展,它将返回一个双精度值。无论出于何种原因,Decimal 类中都没有返回 Double 或 Floag 的属性或函数。
【问题讨论】:
***.com/a/39890916/1187415 演示了如何将 Decimal 转换为 Double。但请注意,这可能会丢失精度,因此自定义断言可能是更好的解决方案。 【参考方案1】:如果没有必要,不要将Decimal
转换为浮点数,因为这会导致精度损失。如果您想比较两个 Decimal
值的准确性,您可以使用 Decimal.distance(to:)
函数,如下所示:
let other = Decimal(35716) / Decimal(10) // 3571.6
let absoluteDistance = abs(position.totalCost.distance(to: other))
let accuracy = Decimal(1) / Decimal(100) // 0.01
XCTAssertTrue(absoluteDistance < accuracy)
【讨论】:
init(floatLiteral:)
: “不要直接调用这个初始化器。”
另一个问题(比较***.com/q/42781785/1187415):print(Decimal(floatLiteral : 1.66)) // 1.6599999999999995904
您可以减去小数点:abs(totalCost - other)
或 (totalCost - other).magnitude
可能更易读。【参考方案2】:
您真的需要指定0.01
的accuracy
吗?
因为如果你省略这个参数,它编译得很好。
struct Position
let totalCost: Decimal
let position = Position(totalCost: 3571.6)
//passes
XCTAssertEqual(position.totalCost, 3571.6)
// XCTAssertEqual failed: ("3571.6") is not equal to ("3571.61")
XCTAssertEqual(position.totalCost, 3571.61)
【讨论】:
但是由于舍入和表示错误,一般不能使用计算得出的小数相等。 谢谢,是的,它在省略准确性参数时确实有效。但是,正如@matt 所说,该代码不适用于所有值。不要使用 3571.6,而是尝试 0.12345。 在你的问题中,你说这有效:XCTAssertTrue(position.totalCost == 3571.6)
@matt 确实如此,但这个问题是关于在特定单元测试用例的上下文中使用XCTAssertEqual
,我的回答在那个上下文中是有效的。我已经使用这种方法编写了许多测试用例而没有问题,因为我正在设置特定条件。以上是关于在 XCTAssertEqual 中使用 Foundation Decimal 类型的主要内容,如果未能解决你的问题,请参考以下文章
使用带有 NSString 的 XCTAssertEqual 作为错误消息参数
比较单元测试中的 swift Type 值 - XCTAssertEqual vs ==
XCTAssertEqual with Optional (not Equatable)
如何使用自定义对象 XCTAssertEqual NSArray?
找不到接受类型参数列表的 XCTAssertEqual 的重载 ([String : AnyObject], [String : AnyObject])