0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

StoreKitTestで購入キャンセル処理のテストを書く

Posted at

概要

StoreKitTestを使って、課金キャンセル処理のユニットテストを書きたかった。
最初利用しようと思っていたSKTestSessionのプロパティがDeperecatedになっていたので、別の方法で実装しようとした。
→少し詰まったので、その備忘録

実装(Deperecated)

課金処理を管理するPurchaseManagerクラスでは、以下のように、支払い処理の結果に応じてStateを切り替えているので、caseが.userCancelledになった時のstateをチェックするテストを書く必要がある。


func purchase(_ product: Product) async {
        do {
            let result = try await product.purchase()
            
            switch result {
            case let .success(.verified(transaction)):
                await transaction.finish()
                await self.updatePurchasedProducts()
                state = .success
            case .success(.unverified(_, _)), .pending:
                state = .idle
                break
            case .userCancelled:
                state = .failure(.canceled)
                break
            @unknown default:
                state = .failure(.unknown)
                break
            }
        } catch {
            state = .failure(.unknown)
     }   
 }

そこで購入キャンセル時のテストケースを以下のように書いた。


final class PurchaseManagerTest: XCTestCase {
    
    var session: SKTestSession!
    var purchaseManager: PurchaseManager!

    // setUpは記載省略

    func testPurchaseCancellation() async throws {
        // 購入キャンセルの設定
        session.failTransactionsEnabled = true // deperecated
        session.failureError = SKError.paymentCancelled //deperecated
        
        try await purchaseManager.loadProducts()
        let product = purchaseManager.product
        
        await purchaseManager.purchase(purchaseManager.product)
        
        // 購入がキャンセルされたことを確認
        XCTAssertEqual(purchaseManager.state, .failure(.canceled))
    }

}

が、sessionをキャンセル状態に設定するところで、iOS17以降でdeperecatedになっている旨の警告が出た。
ドキュメント

スクリーンショット 2024-09-27 0.37.05.png

そもそもテストも通らなかったので、SKError.paymentCancelledを指定しているのが間違っている様子。(単純に理解が浅かった)

と言うわけで、別のコードに書き換えを実施。

実装(修正版)

simulatedError(forAPI:)を使えと警告が出ていたが、課金キャンセル処理を設定したい場合使うのはsetSimulatedError<API>(API.Failure?, forAPI: API)の方だった。

WWDC2023の動画に解説があったのでそちらを元に修正。

修正後のテストケースはこちら。


final class PurchaseManagerTest: XCTestCase {
    
    var session: SKTestSession!
    var purchaseManager: PurchaseManager!

    // setUpは記載省略

    func testPurchaseCancellation() async throws {
        // 購入キャンセルの設定
        try await session.setSimulatedError(
                StoreKitPurchaseAPI.Failure.generic(.userCancelled),
                forAPI: StoreKitPurchaseAPI.purchase
        )
        
        try await purchaseManager.loadProducts()
        let product = purchaseManager.product
        
        await purchaseManager.purchase(purchaseManager.product)
        
        // 購入がキャンセルされたことを確認
        XCTAssertEqual(purchaseManager.state, .failure(.canceled))
    }

}

無事テストも通るようになり、めでたしめでたし。

genericがピンと来なかったので、型を明示的に書いているけれど、もちろん以下のように型省略でも書けます。

try await session.setSimulatedError(.generic(.userCancelled), forAPI: .purchase)

終わりに

やはり公式を見るのが一番だったのだけれど、ドキュメントは説明これしか書いていなかったので、もうちょっとリファレンス充実させてほしい気もする...
スクリーンショット 2024-09-27 1.10.55.png

わかれば簡単だったが、意外と参考資料がなくて少し詰まったところなので、本記事が参考になれば幸いです。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?