在 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.01accuracy 吗?

因为如果你省略这个参数,它编译得很好。

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])

vuejs Newline required at end of file but not foun