前语
StoreKit 结构的第2次迭代是我在过去几年中运用程序中最重大的改变。最近版本的 StoreKit 结构已彻底采用了 Swift 言语特性,如 async 和 await。本篇内容咱们将讨论 StoreKitTest 结构,这不是 StoreKit 2 的一部分,但与之严密耦合。
StoreKitTest
结构为咱们供给了 SKTestSession
类型。运用 SKTestSession
类型的实例,咱们能够购买运用内产品、办理买卖、退款和过期订阅等。
创立一个 StoreKit Demo
咱们从创立一个 StoreKit
相关功用的测验用例开始。我通常有一个称为 SettingsStore
的类型,它定义用户配置并处理运用内购买。咱们将运用 StoreKitTest
结构经过测验来掩盖 SettingsStore
的运用内购买办理部分。
Copy code
@MainActor final class StoreKitTests: XCTestCase {
func testProductPurchase() async throws {
let session = try SKTestSession(configurationFileNamed: "SugarBot Food Calorie Counter")
session.disableDialogs = true
session.clearTransactions()
}
}
如上例所示,咱们初始化了 SKTestSession
类型的实例。然后,咱们调用 clearTransactions
函数来删去咱们可能从曾经的启动中存储的所有买卖。咱们还关闭对话框以轻松自动化购买承认流程。
运用 SKTestSession
现在,咱们能够运用咱们的 SettingsStore
类型来购买产品并处理订阅状况。SKTestSession
类型还答应咱们购买一个模仿运用外购买的产品。例如,可能是一个启用了家庭同享的已购买产品。
Copy code
@MainActor final class StoreKitTests: XCTestCase {
var store: SettingsStore!
override func setUp() {
store = SettingsStore()
}
func testProductPurchase() async throws {
let session = try SKTestSession(configurationFileNamed: "SugarBot Food Calorie Counter")
session.disableDialogs = true
session.clearTransactions()
try await session.buyProduct(identifier: "annual")
guard let product = try await Product.products(for: ["annual"]).first else {
return XCTFail("Can't load products...")
}
let status = try await product.subscription?.status ?? []
await store.processSubscriptionStatus(status)
XCTAssertFalse(store.activeSubscriptions.isEmpty)
}
}
如上例所示,咱们运用 SKTestSession
类型的 buyProduct
函数来模仿购买。咱们还能够运用 SKTestSession
类型的 expireSubscription
函数来过期进行中的订阅,并验证咱们的运用程序怎么处理这些数据。
Copy code
@MainActor final class StoreKitTests: XCTestCase {
var store: SettingsStore!
override func setUp() {
store = SettingsStore()
}
func testExpiredProduct() async throws {
let session = try SKTestSession(configurationFileNamed: "SugarBot Food Calorie Counter")
session.disableDialogs = true
session.clearTransactions()
let transaction = try await session.buyProduct(identifier: "annual")
let activeProducts = try await Product.products(for: ["annual"])
let activeStatus = try await activeProducts.first?.subscription?.status ?? []
await store.processSubscriptionStatus(activeStatus)
XCTAssertFalse(store.activeSubscriptions.isEmpty)
try session.expireSubscription(productIdentifier: "annual")
let expiredProducts = try await Product.products(for: ["annual"])
let expiredStatus = try await expiredProducts.first?.subscription?.status ?? []
await store.processSubscriptionStatus(expiredStatus)
XCTAssertTrue(store.activeSubscriptions.isEmpty)
}
}
SKTestSession
类型还答应咱们运用 refundTransaction
函数模仿产品退款。另一个令人兴奋的选项是测验运用程序对买卖更新的反响。
Copy code
let transaction = try await session.buyProduct(identifier: "annual")
// 验证购买 ...
try session.refundTransaction(identifier: UInt(transaction.id))
// 验证退款 ...
askToBuyEnabled 属性
你还能够运用 askToBuyEnabled
属性来启用问询购买功用,然后运用 approveAskToBuyTransaction
或 declineAskToBuyTransaction
函数来同意或回绝购买。在这种状况下,买卖应从挂起更改为成功。
Copy code
session.askToBuyEnabled = true
await store.purchase("annual")
// 验证购买 ...
let declined = store.pendingTrancations.first?.id ?? 0
try session.declineAskToBuyTransaction(identifier: UInt(declined.id))
// 验证购买 ...
await store.purchase("annual")
// 验证购买 ...
let approved = store.pendingTrancations.first?.id ?? 0
try session.approveAskToBuyTransaction(identifier: UInt(approved.id))
// 验证购买 ...
如上例所示,咱们运用 SKTestSession
类型的实例来模仿问询购买,并验证咱们的运用程序在购买被同意或回绝时的行为。
总结
本文介绍了怎么创立测验用例,然后具体阐明了怎么运用 SKTestSession 类型来模仿购买、退款和订阅过期等状况,并展示了怎么测验运用程序对这些状况的处理。此外,还介绍了运用 askToBuyEnabled 属性启用问询购买功用的办法,并展示了怎么验证运用程序对购买被同意或回绝时的行为。经过这篇文章,读者能够了解怎么运用 StoreKitTest 结构来验证运用程序处理运用内购买和用户流程的能力。