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

Testcontainersでコンテナを使ったテストを実行しよう

Dd39a5beadc52706b9346a922182c4c5?s=47 H.Naka
June 19, 2022

 Testcontainersでコンテナを使ったテストを実行しよう

JJUG CCC 2022 Spring 6月19日開催
[Track A] 10:25- #jjug_ccc_a
#jjug_ccc
Testcontainersでコンテナを使ったテストを実行しよう

Dd39a5beadc52706b9346a922182c4c5?s=128

H.Naka

June 19, 2022
Tweet

Other Decks in Programming

Transcript

  1. None
  2. w ໊͓લɿͳ͔΍·ͻΖʢͤͪʣ 
 5XJUUFS͸ʮͤͪʯ w ͓͠͝ͱɿ౎಺๭8FCαʔϏε w झຯɿήʔϜͱ͓ञͱࣗసं w ӈͷࣸਅ͸(8ʹ૸ͬͨඒϲݪ

    ࣗݾ঺հ
  3. ͜ͷΑ͏ͳ೰Έ͋Γ·ͤΜ͔ʁ w ΞϓϦέʔγϣϯΛ࣮ߦ͢Δ؀ڥߏஙͷେྔͷखॱ͕͋Δ w ྫ͑͹σʔλϕʔεͷΠϯετʔϧ w ΠϯετʔϧΛ׬ྃޙɺςετΛ࣮ߦ͢Δલʹඞཁͳ࡞ۀ w ςετσʔλͷσʔλͷ౤ೖ w

    ࠶౓ςετΛ࣮ߦ͢Δ৔߹͸ݩͷঢ়ଶʹ໭͢ w ࣗಈԽ͸ͦͷ͏͍ͪͨ͠Ͱ͢Ͷɾɾɾʢԕ͍໨ʣ
  4. ͜ͷΑ͏ͳ೰Έ͋Γ·ͤΜ͔ʁ w ෳࡶͳࣄલ४උΛࣗಈԽ͢ΔͨΊɺϏϧυ৬ਓ͕εΫϦϓτΛ࡞੒ w ؤுͬͯߏஙͯ͠΋$*Ͱෆఆظʹ͚͜Δ w ݪҼ͸$*؀ڥͰ͔͠ൃੜ͠ͳ͍ṖͷΤϥʔ w ͦͷ͏ͪΤϥʔʹͳͬͯ΋୭΋ؾʹ͠ͳ͍ɾɾɾ w

    ৬ਓ͸طʹୀ৬Ͱϝϯςφϯε΋Ͱ͖ͳ͍ɾɾɾ
  5. ͜ͷΑ͏ͳ೰Έ͋Γ·ͤΜ͔ʁ w ۤ࿑ͯࣗ͠ಈԽ͚ͨ͠ͲσʔλϕʔεΛ࢖ͬͨςετ͕஗࣮ͯ͘ߦʹ਺े ෼ɾɾɾ w ͜͏ͳͬͨΒςετΛฒྻͰ࣮ߦ͢Δ͔͠ͳ͍ʂ w σʔλͷߋ৽λΠϛϯάͰςετ͕ࣦഊɾɾɾ w σʔλϕʔεΛ૿΍ͦ͏ʹ΋ϙʔτ͕ॏෳɾɾɾ

  6. 5FTUDPOUBJOFSTͰղܾͰ͖Δ͔΋ʁ w 5FTUDPOUBJOFST͸͜Μͳ೰ΈΛղܾͯ͘͠Ε·͢ w ηοτΞοϓ͕ͭΒ͍ˠ+BWBͱ%PDLFS͕Πϯετʔϧ͞Ε͍ͯΕ͹ 0,ʂ w खॱ͕ͭΒ͍ˠςετΫϥε͔Β࢖༻͢ΔίϯςφΛىಈɺޙย෇͚΋ ෆཁ w

    ฒྻ࣮ߦ͕ͭΒ͍ˠςετΫϥε͝ͱʹσʔλϕʔεΛ༻ҙʂϙʔτ໰୊ ΋؆୯ʹղܾ
  7. ຊηογϣϯͷςʔϚ w 5FTUDPOUBJOFSTͷಋೖํ๏͔Β4QSJOH#PPU5FTUͰ࣮ߦ·ͰΛ͝঺հ͠·͢ w ςετର৅͸σʔλϕʔεʢ1PTUHSFTʣΛ࢖ͬͨ8FCΞϓϦέʔγϣϯͰ͢ w ຊεϥΠυͰ͸ιʔείʔυΛஅยతʹష͍ͬͯ·͕͢ɺ(JUIVCͰಈ͘΋ͷ Λެ։͠·͢

  8. w 5FTUDPOUBJOFSTͱ͸ʁ w ίϯςφΛىಈ͠Α͏ w 4QSJOH#PPU5FTUͱͷ࿈ܞ ΞδΣϯμ

  9. 5FTUDPOUBJOFSTͱ͸ʁ

  10. 5FTUDPOUBJOFSTͱ͸ʁ w +6OJUςετ͔Βܰྔ͔ͭ࢖͍ࣺͯͷ%PDLFSίϯςφΛ࣮ߦ͢ΔϥΠϒϥϦ w ໊લؒҧ͑΍͍͢ͷͰ஫ҙ w 5FTU$POUBJOFSTʢ❌ɿ$͕େจࣈʣɺ5FTUDPOUBJOFSʢ❌ɿT͕ͳ͍ʣ w ͞·͟·ͳ044΍঎༻ϓϩμΫτͷςετͰར༻͞Ε͍ͯ·͢ w

    σʔλϕʔεΛར༻ͨ݁͠߹ςετʹ࠷ద w ଞʹ΋4FMFOJVNΛར༻ͨ͠6*ड͚ೖΕςετͰ΋࢖͑·͢
  11. Կ͕͍͍ͷ͔ʁ w ίϯςφͷ؅ཧͷΈʹಛԽͨ͠ϥΠϒϥϦ w ఏڙ͢Δػೳ͕γϯϓϧͳͷͰಋೖʹ͔͔Δֶशίετ͕গͳ͍ w ެ͕ࣜఏڙ͢ΔϞδϡʔϧͰίϯςφ΋ѻ͍΍͘͢ͳ͍ͬͯ·͢ w Ϟδϡʔϧʹ͍ͭͯ͸ޙ΄Ͳղઆ͠·͢

  12. ίϯςφΛىಈ͠Α͏

  13. ࣮ߦ४උ ඞཁ؀ڥ w %PDLFS🐳 w WҎ্ w 8JOEPXTͷαϙʔτ͸ϕετΤϑΥʔτ w +BWBͷόʔδϣϯʹ͍ͭͯ͸هࡌ͸͋Γ·ͤΜ͕ɺҎ্Ͱ͋Ε͹ಈ͘ͱࢥ͍

    ·͢
  14. ࣮ߦ४උ ϓϩδΣΫτ࡞੒ w ࠓճ͸4QSJOHͷΞϓϦέʔγϣϯͷςετΛ࣮ߦ͢Δͷ͕ΰʔϧͳͷͰɺ 4QSJOH*OJUJBMJ[S͔ΒϓϩδΣΫτΛ࡞੒͠·͢ w 5FTUDPOUBJOFST͸4QSJOH*OJUJBMJ[Sʹొ࿥͞Ε͍ͯ·͢ w σʔλϕʔε͸1PTUHSF42-Λબ୒͠·͢

  15. ४උ ґଘੑͷ֬ೝ w ϓϩδΣΫτΛੜ੒͢ΔͱQPNYNMʹ5FTUDPOUBJOFSTͷґଘੑ͕ͭೖͬͯ ͍·͢ w ্͸+6OJUͱ૊Έ߹ΘͤΔϥΠϒϥϦɺԼ͸1PTUHSF42-ͷϞδϡʔϧΛఏ ڙ͢ΔϥΠϒϥϦͰ͢ <dependency> <groupId>org.testcontainers</groupId>

    <artifactId>junit-jupiter</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.testcontainers</groupId> <artifactId>postgresql</artifactId> <scope>test</scope> </dependency>
  16. ิ଍ Ϟδϡʔϧʹ͍ͭͯ w ͜͜·ͰԿճ͔ग़͖͍ͯͯΔʮϞδϡʔϧʯʹ͍ͭͯ؆୯ʹઆ໌͠·͢ w 5FTUDPOUBJOFST͸(FOFSJD$POUBJOFSͱ͍͏ίϯςφΛ࣮ߦ͢ΔͨΊͷڞ௨ తͳػೳΛ࣋ͭΫϥεΛఏڙ͠·͢ w (FOFSJD$POUBJOFSΛܧঝͯ͠ಛఆͷίϯςφʹಛԽͨ͠΋ͷΛϞδϡʔϧͱ ݺΜͰ͍·͢

  17. ิ଍ ϞδϡʔϧʹͰ͖Δ͜ͱ w Ϟδϡʔϧ͸(FOFSJD$POUBJOFSͷઃఆ߲໨ʹ௥Ճͯ͠ɺ࣮ߦ͢Δίϯςφݻ ༗ͷઃఆΛఏڙ͠·͢ w 1PTUHSFTϞδϡʔϧͰ͋Ε͹σʔλϕʔεͷઃఆ͕௥Ճ͞Ε͍ͯ·͢ (FOFSJD$POUBJOFSͷઃఆ߲໨ 1PTUHSFTϞδϡʔϧͷ௥Ճઃఆ߲໨ ࣮ߦ͢ΔΠϝʔδ

    σʔλϕʔε໊ ެ։͢Δϙʔτ ઀ଓϢʔβʔ Ϛ΢ϯτ͢ΔϘϦϡʔϜ ύεϫʔυ
  18. ิ଍ 5FTUDPOUBJOFS͕ఏڙ͢ΔϞδϡʔϧʢൈਮʣ w 5FTUDPOUBJOFST͕ఏڙ͍ͯ͠ΔϞδϡʔϧʹ͸ҎԼͷΑ͏ͳ΋ͷ͕ἧ͍ͬͯ ·͢ʢ͜ΕͰશྔͰ͸ͳ͍Ͱ͢ʣ w ఏڙ͞Ε͍ͯͳ͍ίϯςφͰ΋ɺཁ๬͕ଟ͚Ε͹Ϟδϡʔϧͱͯ͠ొ࿥͞ΕΔ ͔΋͠Ε·ͤΜ 3%#$ $BTTBOESB

    $PDLSPBDI%# .Z42- 0SBDMF9& %# .BSJB%# .POHP%# .PDLTFSWFS -PDBM4UBDL 42-4FSWFS 3BCCJU.2 ,BGLB &MBTUJDTFBSDI 4FMFOJVN
  19. ίϯςφΛ࣮ߦ͠Α͏ w 5FTUDPOUBJOFSTͰίϯςφΛىಈ͢Δํ๏͸͍͔ͭ͋͘Γ·͢ w ࠓճ͸4QSJOH#PPU5FTUʹ૊ΈࠐΈ΍͍͢ΞϊςʔγϣϯΛར༻ͨ͠ํ๏Λ঺ հ͠·͢

  20. ίϯςφΛ࣮ߦ͠Α͏ ςετΫϥε΁ͷΞϊςʔγϣϯͷ෇༩ w ίϯςφΛར༻͢ΔςετΫϥεʹ!5FTUDPOUBJOFSTΞϊςʔγϣϯΛ෇༩ ͠·͢ w 5FTUDPOUBJOFST͸͜ͷΞϊςʔγϣϯ͕͍ͭͨςετΛ࣮ߦ͢Δࡍʹίϯς φΛىಈͯ͘͠Ε·͢ @Testcontainers public

    class ContainerTest {
  21. ίϯςφΛ࣮ߦ͠Α͏ ࣮ߦ͢Δίϯςφͷఆٛ w ࣮ߦ͢ΔίϯςφΛςετΫϥεͷTUBUJDϑΟʔϧυͰఆٛ͠·͢ w ΠϯελϯεॳظԽ࣌ʹίϯςφͷઃఆΛߦ͍·͢ w ࠓճ͸σʔλϕʔε໊ͱ%%-Λఆٛͨ͠42-ϑΝΠϧΛಡΈࠐ·ͤ·͢ w ෳ਺ͷίϯςφΛಉ࣌ʹىಈ͍ͨ͠৔߹͸ϑΟʔϧυΛෳ਺ఆ͍ٛͯͩ͘͠͞

    @Container private static PostgreSQLContainer postgresqlContainer = (PostgreSQLContainer)new PostgreSQLContainer("postgres:14.2") .withDatabaseName("todo") .withInitScript("todo.sql");
  22. ίϯςφΛ࣮ߦ͠Α͏ ࣮ߦͯ͠ΈΑ͏ w ίϯςφͷఆ͕ٛऴΘͬͨΒςετΛ࣮ߦ͠·͢ w ςετΛ࣮ߦ͢Δͱ࠷ॳʹ5FTUDPOUJBOFST͕ఆٛ͞ΕͨίϯςφΛىಈ͠· ͢ w ͦͷޙɺςετϝιου͕ݺͼग़͞Ε·͢ w

    ͨͬͨ͜Ε͚ͩ४උͰςετͰར༻͢Δ؀ڥ͕ηοτΞοϓ͞Ε·ͨ͠ @Test void ίϯςφ͕ಈ͍͍ͯΔ͜ͱ() { assertTrue(postgresqlContainer.isRunning()); }
  23. ίϯςφΛ࣮ߦ͠Α͏ ىಈͨ͠ίϯςφͷޙ࢝຤ w ىಈͨ͠ίϯςφΛఀࢭͨ͠Γ࡟আͨ͠Γ͢Δॲཧ͸શ෦5FTUDPOUBJOFST͕ ΍ͬͯ͘Ε·͢ w ίϯςφɾϘϦϡʔϜɾωοτϫʔΫͷશͯΛ࡟আͯ͘͠Ε·͢ w ޙ࢝຤͸5FTUDPOUBJOFSTʹ೚ͤͯςετΛॻ͘ͷʹઐ೦͠·͠ΐ͏ w

    ༨ஊͰ͕͢ίϯςφΛ࡟আͯ͘͠ΕΔͷ͸Ϧϯΰ͕޷͖ͳࢮਆͰ͢ w ϦϡʔΫͱ͍͏໊ͷίϯςφ͕ཪͰ͓૟আͯ͠·͢
  24. ίϯςφ࣮ߦͷิ଍ ϩάϨϕϧͷઃఆʢ೚ҙʣ w σϑΥϧτͷϩάϨϕϧͰ͸ɺίϯςφͷ1VMM΍ىಈ࣌ʹϩά͕େྔग़ྗ͞Ε ͯ͠·͍·͢ w ϩά͕ଟ͗͢Δͱײͨ͡৔߹͸5FTUDPOUBJOFSTͷग़ྗϨϕϧΛߜͬͯͩ͘͞ ͍ w ެࣜ)1ʹMPHCBDLUFTUYNM͕ఏڙ͞Ε͍ͯ·͢

  25. ίϯςφ࣮ߦͷิ଍ खಈͰͷίϯςφىಈ w ΞϊςʔγϣϯΛར༻͠ͳ͍৔߹ɺOFXͨ͠ίϯςφΠϯελϯεͷTUBSUϝ ιουΛݺͼग़͢͜ͱͰίϯςφΛىಈ͢Δ͜ͱ͕Ͱ͖·͢ w ͜ͷํ๏Ͱىಈͨ͠৔߹Ͱ΋ίϯςφͷޙ࢝຤͸5FTUDPOUBJOFST͕ߦͬͯ͘ Ε·͢ // ࣮ߦ͢Δίϯςφͷఆٛ

    PostgreSQLContainer postgresqlContainer = (PostgreSQLContainer) new PostgreSQLContainer("postgres:14.2") .withDatabaseName("todo") .withInitScript("todo.sql"); // ىಈ postgresqlContainer.start();
  26. ίϯςφ࣮ߦͷิ଍ ˏ$POUBJOFSͷϑΟʔϧυ w ࠓճ͸ˏ$POUBJOFSΛTUBUJDϑΟʔϧυʹઃఆͨͨ͠ΊɺςετΫϥεͰͭ ͷίϯςφ͕༻ҙ͞Ε·͢ w ͜ΕΛTUBUJDͰ͸ͳ͘ΠϯελϯεϑΟʔϧυʹ෇༩ͨ͠৔߹ɺςετϝιο υ͝ͱʹίϯςφ͕༻ҙ͞Ε·͢

  27. ͜͜·Ͱͷ·ͱΊ w ΞϊςʔγϣϯΛ࢖͏͚ͩͰ؆୯ʹίϯςφΛ૊ΈࠐΊΔ͜ͱΛ঺հ͠·ͨ͠ w ͜ΕͰ4QSJOHͷΞϓϦέʔγϣϯͰར༻͢Δσʔλϕʔεͷ४උ͸੔͍·͠ ͨ w ࣍͸ىಈͨ͠σʔλϕʔεΛ4QSJOH#PPU͔Β࢖͏ํ๏Λ঺հ͠·͢

  28. 4QSJOH#PPU5FTUͱͷ࿈ܞ

  29. ςετ͢ΔΞϓϦέʔγϣϯ w ςετର৅ͷΞϓϦέʔγϣϯͱͯ͠ɺ؆୯ͳ5PEPͷΞϓϦΛར༻͠·͢ w ͜ͷΞϓϦͷ4FSWJDFΫϥεʹରͯ͠ɺ4QSJOH#PPU5FTUΛ࢖ͬͨ݁߹ςετ Λ࣮ߦ͠·͢ @Transactional Todo addTodo(String task)

    { return repository.save(new Todo(null,task,"Waiting")); }
  30. 4QSJOH#PPU5FTU ςετ࣮૷ w 5FTUDPOUBJOFSTΛઃఆͨ͠ςετΫϥεʹҎԼͷͭΛ௥Ճ͠·͢ w 4QSJOH#PPU5FTUΞϊςʔγϣϯΛ෇༩͢Δ w 4QSJOHͷΞϓϦʹ5FTUDPOUBJOFSTͰىಈͨ͠σʔλϕʔε΁ͷ઀ଓ৘ใΛ ࢦఆ͢Δ w

    ςετΫϥεʹςετ͢Δ4FSWJDFΫϥεΛ%*ͯ͠ςετϝιου͔Β࣮ߦ w ࠓ·Ͱͷ4QSJOH#PPUςετʹ੺࿮ͰғͬͨॲཧΛ௥Ճ͢Δ͚ͩͰ͢
  31. 4QSJOH#PPU5FTU σʔλϕʔεͷ઀ଓఆٛΛઃఆ w σʔλϕʔεͷ઀ଓઃఆ͸ɺ%ZOBNJD1SPQFSUZ4PVSDFΛ෇༩ͨ͠ϝιου ಺Ͱઃఆ͠·͢ w ઀ଓ৘ใ͸શͯίϯςφΠϯελϯε͔ΒऔಘՄೳͰ͢ w ༨ஊͰ͕͢͜ͷΞϊςʔγϣϯ͸4QSJOH͕5FTUDPOUBJOFSTͷͨΊʹ༻ҙͨ͠ ΋ͷͰ͢

    @DynamicPropertySource static void jdbcProperties(DynamicPropertyRegistry registry) { registry.add("spring.datasource.url", postgresqlContainer::getJdbcUrl); registry.add("spring.datasource.username", postgresqlContainer::getUsername); registry.add("spring.datasource.password", postgresqlContainer::getPassword); }
  32. 4QSJOH#PPU5FTU ςετ࣮ߦ w ςετϝιουͰ4QSJOHͷαʔϏεΫϥεΛݺͼग़͢ςετΛهड़͠·͢ w ςετΛىಈ͢Δͱίϯςφͷσʔλϕʔεͱ4QSJOH͕ىಈ͠ɺςετϝι ου಺ͷॲཧ͕͓͜ͳΘΕ·͢ w ͜ΕͰσʔλϕʔεΛ༻͍ͨΞϓϦέʔγϣϯͷ݁߹ςετ͕ߦ͑·ͨ͠ @Autowired

    private TodoService service; @Test @Order(1) void addTodo() { String task = "🐱ʹ͝൧Λ΋Β͏"; Todo todo = service.addTodo(task); assertEquals(task, todo.task()); assertEquals("Waiting", todo.status()); }
  33. 4QSJOH#PPU5FTUิ଍ &YUFOTJPOΫϥεͰͷ࣮ߦ w ࠓճ͸ΞϊςʔγϣϯΛ༻͍ͨγϯϓϧͳํ๏Λ঺հ͠·ͨ͠ w Ξϊςʔγϣϯͷ৔߹͸֤ΫϥεͰίϯςφͷఆٛΛߦ͏ඞཁ͕͋Γ·͕͢ɺ ͜ͷఆٛΛ+6OJUͷ&YUFOTJPOΛ༻͍ͯू໿͢Δํ๏΋͋Γ·͢ w (JUIVCʹαϯϓϧͷίʔυ͕͋Γ·͢ͷͰࢀরͯ͠Έ͍ͯͩ͘͞ public

    class PostgresExtension implements BeforeAllCallback, AfterAllCallback { private PostgreSQLContainer<?> postgresqlContainer; @Override public void beforeAll(ExtensionContext context) { postgresqlContainer = (PostgreSQLContainer) new PostgreSQLContainer("postgres:14.2") .withDatabaseName("todo"); postgresqlContainer.start(); System.setProperty("spring.datasource.url", postgresqlContainer.getJdbcUrl()); System.setProperty("spring.datasource.username", postgresqlContainer.getUsername()); System.setProperty("spring.datasource.password", postgresqlContainer.getPassword()); }
  34. 4QSJOH#PPU5FTUิ଍ 5FTUDPOUBJOFSTͷόʔδϣϯ w 4QSJOH*OJUJBMJ[SͰ࡞੒ͨ͠ϓϩδΣΫτͷ5FTUDPOUBJOFSTͷόʔδϣϯ͸ Ͱ͢ w Ҏ߱Ͱ௥Ճ͞ΕͨϞδϡʔϧΛར༻͍ͨ͠৔߹͸ɺόʔδϣϯΛࢦఆ ͢Δඞཁ͕͋Γ·͢ʢࠓͷ࠷৽͸ʣ w ௥Ճ͞ΕͨϞδϡʔϧ͸4FMFOJVNɺLTɺ)JWF.2ͷͭͰ͢

  35. ·ͱΊ

  36. 5FTUDPOUBJOFSTͷಋೖޮՌ w ࠓ೔঺հͨ͠ൣғͰ΋5FTUDPOUBJOFST͸ͨ͘͞Μͷ࢓ࣄΛͯ͠·͢ w σʔλϕʔεͷΠϯετʔϧ͔Β࡟আ·ͰΛςετΫϥεͱີʹ࿈ܞ w ʮ+BWBͱ%PDLFS͕͋Ε͹Ͳ͜ͷϚγϯͰ΋੒ޭ͢Δςετʯ͕࡞ΕΔؾ͕͠ ͖ͯ·ͤΜ͔ʁ w গͳ͘ͱ΋ΞϓϦ΍ςετʹؔ܎ͳ͍໰୊Ͱɺ։ൃऀͷखΛ൥ΘͤΔ࣌ؒ΍࿑

    ྗ͸࣮֬ʹݮΓ·͢
  37. ·ͱΊ w ೉қ౓ͱൺֱͯ͠5FTUDPOUBJOFSTͷՌͨ͢໾ׂ͸େ͖͍ͱࢥ͍·͢ w ݸਓతʹ஍ຯ͚ͩͲ࢓ࣄΛ࣮֬ʹ͜ͳͯ͘͠ΕΔ࢓ࣄਓελΠϧͳͱ͜Ζ͕޷ ͖Ͱ͢ w ϋϚΓϙΠϯτ͸େମ͸࣮ߦ͢Δίϯςφͷ࢓༷ɾɾɾ w ࠓճ͸4QSJOHͱͷ૊Έ߹ΘͤΛ঺հ͠·͕ͨ͠ɺผͷϑϨʔϜϫʔΫʢྫ͑͹

    2VBSLVTʣͱ΋࿈ܞ͢Δ͜ͱ͕Ͱ͖·͢ w ܁Γฦ͠ʹͳΓ·͕͢ɺςετ؀ڥͷ४උͱ͔໘౗ͳ͜ͱ͸શ෦ 5FTUDPOUBJOFSTʹ೚ͤ·͠ΐ͏ʂ w ։ൃऀ͸͍͍ίʔυΛॻ͘͜ͱʹઐ೦͠Α͏ʂ
  38. ࢀߟࢿྉ w IUUQTXXXUFTUDPOUBJOFSTPSH w ެࣜ)1͸υΩϡϝϯτ͕ॆ࣮ w (JUIVCͷFYBNQMFʹ͸༷ʑͳϞδϡʔϧͷαϯϓϧ΋͋Γ·͢ w IUUQTHJUIVCDPNXFOBTTQSJOHUDFYBNQMF w

    ຊηογϣϯͷεϥΠυʹషͬͨίʔυ w શͯΛ঺հͰ͖·ͤΜͰͨ͠ͷͰɺ΋͠ΑΖ͚͠Ε͹ࢀর͍ͯͩ͘͠͞
  39. ίϯςφςετֵ໋ 🐳