Upgrade to Pro — share decks privately, control downloads, hide ads and more …

「テストは愚直&&網羅的に書くほどよい」という誤解 / Test Smarter, Not H...

「テストは愚直&&網羅的に書くほどよい」という誤解 / Test Smarter, Not Harder

"モバイルアプリのテストコードどうしてる? 現場Tips共有会" ( https://findy-tools.connpass.com/event/359490/ ) での発表資料です。

Avatar for Munetoshi Ishikawa

Munetoshi Ishikawa

July 07, 2025
Tweet

More Decks by Munetoshi Ishikawa

Other Decks in Programming

Transcript

  1. ΞΧ΢ϯτछผ'SFF 4UBOEBSE 1MVT ʜ 1SPGFTTJPOBM 6MUJNBUF  छผมߋͰ͋ΓಘΔέʔε  'SFFˠ1MVT

    4UBOEBSEˠ1MVT 1MVTˠ1MVT ʜ  ੾Γସ͑੒ޭ ࣦഊ ωοτϫʔΫ ೝূ ظؒ ܾࡁ ʜ έʔεελσΟΞΧ΢ϯτछผมߋ
  2. ࣅͨΑ͏ͳςετίʔυͷେྔൃੜ class UpdateAccountTypeUseCaseTest : FunSpec({ test("Changes successfully the account type

    from Free to Plus") { /*...setup...*/ repository.setCurrentAccountType(AccountType.FREE) val result = useCase.execute(AccountType.PLUS) result shouldBe UpgradeResult.Success repository.getCurrentAccountType() shouldBe AccountType.PLUS } test("Changes successfully the account type from Standard to Plus") { /*...similar setup...*/ repository.setCurrentAccountType(AccountType.STANDARD) /*...similar action & verification...*/ } test(/*...similar test...*/) { /*...*/ }; test(/*...*/) { /*...*/ }; /*...*/ έʔεελσΟΞΧ΢ϯτछผมߋ
  3. class UpdateAccountTypeUseCaseTest : FunSpec({ test("Changes successfully the account type from

    Free to Plus") { val repository = AccountRepository(/*...*/) val useCase = UpdateAccountTypeUseCase(/*...*/) repository.setCurrentAccountType(AccountType.FREE) val result = useCase.execute(AccountType.PLUS) result shouldBe UpgradeResult.Success repository.getCurrentAccountType() shouldBe AccountType.PLUS } test("Changes successfully the account type from Standard to Plus") { /*...similar setup...*/ val result = useCase.execute(AccountType.PLUS) /*...similar verification...*/ } έʔεΛந৅Խ෼ղ͢Δ
  4. class UpdateAccountTypeUseCaseTest : FunSpec({ test("Upgrades successfully the account type") {

    val repository = AccountRepository(/*...*/) val useCase = UpdateAccountTypeUseCase(/*...*/) repository.setCurrentAccountType(AccountType.FREE) val result = useCase.execute(AccountType.PLUS) result shouldBe UpgradeResult.Success repository.getCurrentAccountType() shouldBe AccountType.PLUS } έʔεΛந৅Խ෼ղ͢Δ
  5. class CreateAccountUseCase { fun execute(accountName: String, email: String, type: AccountType):

    CreationResult { if (type == AccountType.ADMIN) { return CreationResult.Failure(ErrorType.INVALID_ACCOUNT_TYPE) } /*...*/ return CreationResult.Success } ੩తݕূʹஔ͖׵͑Δ
  6. class CreateAccountUseCase { fun execute(request: CreateAccountRequest): CreationResult { /*...*/ return

    CreationResult.Success } class CreateAccountRequest private constructor(accountName: String, /*...*/) { companion object { fun of(/*...*/): CreateAccountRequest? = if (type != AccountType.ADMIN) CreateAccountRequest(/*...*/) else null } } ੩తݕূʹஔ͖׵͑Δ
  7. ϑϨʔϜϫʔΫͷ࢓૊Έ͔ϧʔϓΛ࢖͏ data class TestParams(val accountName: String, val isValid: Boolean, val

    description: String) context("Creates account for names") { withData( TestParams("", false, "Empty name is invalid"), TestParams("My account", false, "Name with whitespaces is invalid"), TestParams("myaccount", true, "Valid name with only lowercase letters"), /*...*/ ) { (accountName, isValid) -> val request = CreateAccountRequest.of(accountName, "", AccountType.FREE) (request != null) shouldBe isValid } } έʔεͷҧ͍ͱ໢ཏੑ͕෼͔Γ΍͘͢ͳΔ ύϥϝʔλͱϩδοΫΛ෼཭͢Δ
  8. ςετϩδοΫΛ෦෼తʹ·ͱΊΔ  ྫ'BLF 'BDUPSZ 'JYUVSF ʜ  ର৅ηοτΞοϓ ݕূ ςΟΞμ΢ϯ

    ʜ  ޮՌந৅ԽʹΑΔςετՄಡੑͷ޲্ ෼ذ͸5FTU6UJMJUZ಺ͳΒڐ༰͞ΕΔ͜ͱ΋͋Δ  6UJMJUZࣗମΛςετՄೳ܁Γฦ͠ͷར༻ʹΑΔݕূ 5FTU6UJMJUZΛ࡞Δ