Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Testcontainersでコンテナを使ったテストを実行しよう
Search
H.Naka
June 19, 2022
Programming
2
870
Testcontainersでコンテナを使ったテストを実行しよう
JJUG CCC 2022 Spring 6月19日開催
[Track A] 10:25- #jjug_ccc_a
#jjug_ccc
Testcontainersでコンテナを使ったテストを実行しよう
H.Naka
June 19, 2022
Tweet
Share
More Decks by H.Naka
See All by H.Naka
JJUG_CCC_2023_Exposed.pdf
wenas
0
270
Other Decks in Programming
See All in Programming
Some Quick Ideas To Improve Your Tests ( #jassttokyo )
teyamagu
PRO
2
2.3k
RubyVM を PHP で実装する 〜Hello World を出力するまで〜
memory1994
PRO
1
490
PHPerKaigi 2024〜10年以上動いているレガシーなバッチシステムを Kubernetes(Amazon EKS) に移行する取り組み〜
tshinowpub
1
220
ONE WEDGE_Company_Information
1wedge
0
180
Laravel標準バリデーションでできること
hmb_ok
2
360
もうすぐ新年度、Babylon.jsがお勧めな3個の理由
hideg
0
170
実践!RDRAを活用した既存システムの仕様変更 / Specification Changes in Existing Systems Utilizing RDRA
imamotohikaru
0
2.7k
TCAの Shared Stateって どういう仕組みになってんの?
yimajo
0
330
PHP8の機能を使って堅牢にコードを書く
fendo181
6
2.6k
CircleCIを活用して AWSへの継続的デリバリーを 実践する
coconala_engineer
1
110
Dockerで始めるAWS Lambda開発
stutkhd0709
14
2.5k
複雑なドメインを扱うプロダクトの探索フェーズではいつどのようにテストをするのか / How to testing during exploratory phase
boykush
2
150
Featured
See All Featured
Let's Do A Bunch of Simple Stuff to Make Websites Faster
chriscoyier
501
140k
Optimising Largest Contentful Paint
csswizardry
7
2.3k
The Success of Rails: Ensuring Growth for the Next 100 Years
eileencodes
28
5.9k
Making Projects Easy
brettharned
106
5.4k
Designing for humans not robots
tammielis
247
25k
Designing on Purpose - Digital PM Summit 2013
jponch
109
6.4k
Automating Front-end Workflow
addyosmani
1353
200k
[RailsConf 2023] Rails as a piece of cake
palkan
21
3.8k
4 Signs Your Business is Dying
shpigford
174
21k
Principles of Awesome APIs and How to Build Them.
keavy
119
16k
Designing with Data
zakiwarfel
94
4.8k
The Illustrated Children's Guide to Kubernetes
chrisshort
28
46k
Transcript
None
w ໊͓લɿͳ͔·ͻΖʢͤͪʣ 5XJUUFSʮͤͪʯ w ͓͠͝ͱɿ8FCαʔϏε w झຯɿήʔϜͱ͓ञͱࣗసं w ӈͷࣸਅ(8ʹͬͨඒϲݪ
ࣗݾհ
͜ͷΑ͏ͳΈ͋Γ·ͤΜ͔ʁ w ΞϓϦέʔγϣϯΛ࣮ߦ͢Δڥߏஙͷେྔͷखॱ͕͋Δ w ྫ͑σʔλϕʔεͷΠϯετʔϧ w ΠϯετʔϧΛྃޙɺςετΛ࣮ߦ͢Δલʹඞཁͳ࡞ۀ w ςετσʔλͷσʔλͷೖ w
࠶ςετΛ࣮ߦ͢Δ߹ݩͷঢ়ଶʹ͢ w ࣗಈԽͦͷ͏͍ͪͨ͠Ͱ͢Ͷɾɾɾʢԕ͍ʣ
͜ͷΑ͏ͳΈ͋Γ·ͤΜ͔ʁ w ෳࡶͳࣄલ४උΛࣗಈԽ͢ΔͨΊɺϏϧυ৬ਓ͕εΫϦϓτΛ࡞ w ؤுͬͯߏஙͯ͠$*Ͱෆఆظʹ͚͜Δ w ݪҼ$*ڥͰ͔͠ൃੜ͠ͳ͍ṖͷΤϥʔ w ͦͷ͏ͪΤϥʔʹͳͬͯ୭ؾʹ͠ͳ͍ɾɾɾ w
৬ਓطʹୀ৬ͰϝϯςφϯεͰ͖ͳ͍ɾɾɾ
͜ͷΑ͏ͳΈ͋Γ·ͤΜ͔ʁ w ۤ࿑ͯࣗ͠ಈԽ͚ͨ͠ͲσʔλϕʔεΛͬͨςετ͕࣮ͯ͘ߦʹे ɾɾɾ w ͜͏ͳͬͨΒςετΛฒྻͰ࣮ߦ͢Δ͔͠ͳ͍ʂ w σʔλͷߋ৽λΠϛϯάͰςετ͕ࣦഊɾɾɾ w σʔλϕʔεΛ૿ͦ͏ʹϙʔτ͕ॏෳɾɾɾ
5FTUDPOUBJOFSTͰղܾͰ͖Δ͔ʁ w 5FTUDPOUBJOFST͜ΜͳΈΛղܾͯ͘͠Ε·͢ w ηοτΞοϓ͕ͭΒ͍ˠ+BWBͱ%PDLFS͕Πϯετʔϧ͞Ε͍ͯΕ 0,ʂ w खॱ͕ͭΒ͍ˠςετΫϥε͔Β༻͢ΔίϯςφΛىಈɺޙย͚ ෆཁ w
ฒྻ࣮ߦ͕ͭΒ͍ˠςετΫϥε͝ͱʹσʔλϕʔεΛ༻ҙʂϙʔτ ؆୯ʹղܾ
ຊηογϣϯͷςʔϚ w 5FTUDPOUBJOFSTͷಋೖํ๏͔Β4QSJOH#PPU5FTUͰ࣮ߦ·ͰΛ͝հ͠·͢ w ςετରσʔλϕʔεʢ1PTUHSFTʣΛͬͨ8FCΞϓϦέʔγϣϯͰ͢ w ຊεϥΠυͰιʔείʔυΛஅยతʹష͍ͬͯ·͕͢ɺ(JUIVCͰಈ͘ͷ Λެ։͠·͢
w 5FTUDPOUBJOFSTͱʁ w ίϯςφΛىಈ͠Α͏ w 4QSJOH#PPU5FTUͱͷ࿈ܞ ΞδΣϯμ
5FTUDPOUBJOFSTͱʁ
5FTUDPOUBJOFSTͱʁ w +6OJUςετ͔Βܰྔ͔͍ࣺͭͯͷ%PDLFSίϯςφΛ࣮ߦ͢ΔϥΠϒϥϦ w ໊લؒҧ͍͑͢ͷͰҙ w 5FTU$POUBJOFSTʢ❌ɿ$͕େจࣈʣɺ5FTUDPOUBJOFSʢ❌ɿT͕ͳ͍ʣ w ͞·͟·ͳ044༻ϓϩμΫτͷςετͰར༻͞Ε͍ͯ·͢ w
σʔλϕʔεΛར༻ͨ݁͠߹ςετʹ࠷ద w ଞʹ4FMFOJVNΛར༻ͨ͠6*ड͚ೖΕςετͰ͑·͢
Կ͕͍͍ͷ͔ʁ w ίϯςφͷཧͷΈʹಛԽͨ͠ϥΠϒϥϦ w ఏڙ͢Δػೳ͕γϯϓϧͳͷͰಋೖʹ͔͔Δֶशίετ͕গͳ͍ w ެ͕ࣜఏڙ͢ΔϞδϡʔϧͰίϯςφѻ͍͘͢ͳ͍ͬͯ·͢ w Ϟδϡʔϧʹ͍ͭͯޙ΄Ͳղઆ͠·͢
ίϯςφΛىಈ͠Α͏
࣮ߦ४උ ඞཁڥ w %PDLFS🐳 w WҎ্ w 8JOEPXTͷαϙʔτϕετΤϑΥʔτ w +BWBͷόʔδϣϯʹ͍ͭͯهࡌ͋Γ·ͤΜ͕ɺҎ্Ͱ͋Εಈ͘ͱࢥ͍
·͢
࣮ߦ४උ ϓϩδΣΫτ࡞ w ࠓճ4QSJOHͷΞϓϦέʔγϣϯͷςετΛ࣮ߦ͢Δͷ͕ΰʔϧͳͷͰɺ 4QSJOH*OJUJBMJ[S͔ΒϓϩδΣΫτΛ࡞͠·͢ w 5FTUDPOUBJOFST4QSJOH*OJUJBMJ[Sʹొ͞Ε͍ͯ·͢ w σʔλϕʔε1PTUHSF42-Λબ͠·͢
४උ ґଘੑͷ֬ೝ 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>
ิ Ϟδϡʔϧʹ͍ͭͯ w ͜͜·ͰԿճ͔ग़͖͍ͯͯΔʮϞδϡʔϧʯʹ͍ͭͯ؆୯ʹઆ໌͠·͢ w 5FTUDPOUBJOFST(FOFSJD$POUBJOFSͱ͍͏ίϯςφΛ࣮ߦ͢ΔͨΊͷڞ௨ తͳػೳΛ࣋ͭΫϥεΛఏڙ͠·͢ w (FOFSJD$POUBJOFSΛܧঝͯ͠ಛఆͷίϯςφʹಛԽͨ͠ͷΛϞδϡʔϧͱ ݺΜͰ͍·͢
ิ ϞδϡʔϧʹͰ͖Δ͜ͱ w Ϟδϡʔϧ(FOFSJD$POUBJOFSͷઃఆ߲ʹՃͯ͠ɺ࣮ߦ͢Δίϯςφݻ ༗ͷઃఆΛఏڙ͠·͢ w 1PTUHSFTϞδϡʔϧͰ͋Εσʔλϕʔεͷઃఆ͕Ճ͞Ε͍ͯ·͢ (FOFSJD$POUBJOFSͷઃఆ߲ 1PTUHSFTϞδϡʔϧͷՃઃఆ߲ ࣮ߦ͢ΔΠϝʔδ
σʔλϕʔε໊ ެ։͢Δϙʔτ ଓϢʔβʔ Ϛϯτ͢ΔϘϦϡʔϜ ύεϫʔυ
ิ 5FTUDPOUBJOFS͕ఏڙ͢ΔϞδϡʔϧʢൈਮʣ w 5FTUDPOUBJOFST͕ఏڙ͍ͯ͠ΔϞδϡʔϧʹҎԼͷΑ͏ͳͷ͕ἧ͍ͬͯ ·͢ʢ͜ΕͰશྔͰͳ͍Ͱ͢ʣ w ఏڙ͞Ε͍ͯͳ͍ίϯςφͰɺཁ͕ଟ͚ΕϞδϡʔϧͱͯ͠ొ͞ΕΔ ͔͠Ε·ͤΜ 3%#$ $BTTBOESB
$PDLSPBDI%# .Z42- 0SBDMF9& %# .BSJB%# .POHP%# .PDLTFSWFS -PDBM4UBDL 42-4FSWFS 3BCCJU.2 ,BGLB &MBTUJDTFBSDI 4FMFOJVN
ίϯςφΛ࣮ߦ͠Α͏ w 5FTUDPOUBJOFSTͰίϯςφΛىಈ͢Δํ๏͍͔ͭ͋͘Γ·͢ w ࠓճ4QSJOH#PPU5FTUʹΈࠐΈ͍͢ΞϊςʔγϣϯΛར༻ͨ͠ํ๏Λ հ͠·͢
ίϯςφΛ࣮ߦ͠Α͏ ςετΫϥεͷΞϊςʔγϣϯͷ༩ w ίϯςφΛར༻͢ΔςετΫϥεʹ!5FTUDPOUBJOFSTΞϊςʔγϣϯΛ༩ ͠·͢ w 5FTUDPOUBJOFST͜ͷΞϊςʔγϣϯ͕͍ͭͨςετΛ࣮ߦ͢Δࡍʹίϯς φΛىಈͯ͘͠Ε·͢ @Testcontainers public
class ContainerTest {
ίϯςφΛ࣮ߦ͠Α͏ ࣮ߦ͢Δίϯςφͷఆٛ w ࣮ߦ͢ΔίϯςφΛςετΫϥεͷTUBUJDϑΟʔϧυͰఆٛ͠·͢ w ΠϯελϯεॳظԽ࣌ʹίϯςφͷઃఆΛߦ͍·͢ w ࠓճσʔλϕʔε໊ͱ%%-Λఆٛͨ͠42-ϑΝΠϧΛಡΈࠐ·ͤ·͢ w ෳͷίϯςφΛಉ࣌ʹىಈ͍ͨ͠߹ϑΟʔϧυΛෳఆ͍ٛͯͩ͘͠͞
@Container private static PostgreSQLContainer postgresqlContainer = (PostgreSQLContainer)new PostgreSQLContainer("postgres:14.2") .withDatabaseName("todo") .withInitScript("todo.sql");
ίϯςφΛ࣮ߦ͠Α͏ ࣮ߦͯ͠ΈΑ͏ w ίϯςφͷఆ͕ٛऴΘͬͨΒςετΛ࣮ߦ͠·͢ w ςετΛ࣮ߦ͢Δͱ࠷ॳʹ5FTUDPOUJBOFST͕ఆٛ͞ΕͨίϯςφΛىಈ͠· ͢ w ͦͷޙɺςετϝιου͕ݺͼग़͞Ε·͢ w
ͨͬͨ͜Ε͚ͩ४උͰςετͰར༻͢Δڥ͕ηοτΞοϓ͞Ε·ͨ͠ @Test void ίϯςφ͕ಈ͍͍ͯΔ͜ͱ() { assertTrue(postgresqlContainer.isRunning()); }
ίϯςφΛ࣮ߦ͠Α͏ ىಈͨ͠ίϯςφͷޙ࢝ w ىಈͨ͠ίϯςφΛఀࢭͨ͠Γআͨ͠Γ͢Δॲཧશ෦5FTUDPOUBJOFST͕ ͬͯ͘Ε·͢ w ίϯςφɾϘϦϡʔϜɾωοτϫʔΫͷશͯΛআͯ͘͠Ε·͢ w ޙ࢝5FTUDPOUBJOFSTʹͤͯςετΛॻ͘ͷʹઐ೦͠·͠ΐ͏ w
༨ஊͰ͕͢ίϯςφΛআͯ͘͠ΕΔͷϦϯΰ͕͖ͳࢮਆͰ͢ w ϦϡʔΫͱ͍͏໊ͷίϯςφ͕ཪͰ͓আͯ͠·͢
ίϯςφ࣮ߦͷิ ϩάϨϕϧͷઃఆʢҙʣ w σϑΥϧτͷϩάϨϕϧͰɺίϯςφͷ1VMMىಈ࣌ʹϩά͕େྔग़ྗ͞Ε ͯ͠·͍·͢ w ϩά͕ଟ͗͢Δͱײͨ͡߹5FTUDPOUBJOFSTͷग़ྗϨϕϧΛߜͬͯͩ͘͞ ͍ w ެࣜ)1ʹMPHCBDLUFTUYNM͕ఏڙ͞Ε͍ͯ·͢
ίϯςφ࣮ߦͷิ खಈͰͷίϯςφىಈ w ΞϊςʔγϣϯΛར༻͠ͳ͍߹ɺOFXͨ͠ίϯςφΠϯελϯεͷTUBSUϝ ιουΛݺͼग़͢͜ͱͰίϯςφΛىಈ͢Δ͜ͱ͕Ͱ͖·͢ w ͜ͷํ๏Ͱىಈͨ͠߹Ͱίϯςφͷޙ࢝5FTUDPOUBJOFST͕ߦͬͯ͘ Ε·͢ // ࣮ߦ͢Δίϯςφͷఆٛ
PostgreSQLContainer postgresqlContainer = (PostgreSQLContainer) new PostgreSQLContainer("postgres:14.2") .withDatabaseName("todo") .withInitScript("todo.sql"); // ىಈ postgresqlContainer.start();
ίϯςφ࣮ߦͷิ ˏ$POUBJOFSͷϑΟʔϧυ w ࠓճˏ$POUBJOFSΛTUBUJDϑΟʔϧυʹઃఆͨͨ͠ΊɺςετΫϥεͰͭ ͷίϯςφ͕༻ҙ͞Ε·͢ w ͜ΕΛTUBUJDͰͳ͘ΠϯελϯεϑΟʔϧυʹ༩ͨ͠߹ɺςετϝιο υ͝ͱʹίϯςφ͕༻ҙ͞Ε·͢
͜͜·Ͱͷ·ͱΊ w ΞϊςʔγϣϯΛ͏͚ͩͰ؆୯ʹίϯςφΛΈࠐΊΔ͜ͱΛհ͠·ͨ͠ w ͜ΕͰ4QSJOHͷΞϓϦέʔγϣϯͰར༻͢Δσʔλϕʔεͷ४උ͍·͠ ͨ w ࣍ىಈͨ͠σʔλϕʔεΛ4QSJOH#PPU͔Β͏ํ๏Λհ͠·͢
4QSJOH#PPU5FTUͱͷ࿈ܞ
ςετ͢ΔΞϓϦέʔγϣϯ w ςετରͷΞϓϦέʔγϣϯͱͯ͠ɺ؆୯ͳ5PEPͷΞϓϦΛར༻͠·͢ w ͜ͷΞϓϦͷ4FSWJDFΫϥεʹରͯ͠ɺ4QSJOH#PPU5FTUΛͬͨ݁߹ςετ Λ࣮ߦ͠·͢ @Transactional Todo addTodo(String task)
{ return repository.save(new Todo(null,task,"Waiting")); }
4QSJOH#PPU5FTU ςετ࣮ w 5FTUDPOUBJOFSTΛઃఆͨ͠ςετΫϥεʹҎԼͷͭΛՃ͠·͢ w 4QSJOH#PPU5FTUΞϊςʔγϣϯΛ༩͢Δ w 4QSJOHͷΞϓϦʹ5FTUDPOUBJOFSTͰىಈͨ͠σʔλϕʔεͷଓใΛ ࢦఆ͢Δ w
ςετΫϥεʹςετ͢Δ4FSWJDFΫϥεΛ%*ͯ͠ςετϝιου͔Β࣮ߦ w ࠓ·Ͱͷ4QSJOH#PPUςετʹͰғͬͨॲཧΛՃ͢Δ͚ͩͰ͢
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); }
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()); }
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()); }
4QSJOH#PPU5FTUิ 5FTUDPOUBJOFSTͷόʔδϣϯ w 4QSJOH*OJUJBMJ[SͰ࡞ͨ͠ϓϩδΣΫτͷ5FTUDPOUBJOFSTͷόʔδϣϯ Ͱ͢ w Ҏ߱ͰՃ͞ΕͨϞδϡʔϧΛར༻͍ͨ͠߹ɺόʔδϣϯΛࢦఆ ͢Δඞཁ͕͋Γ·͢ʢࠓͷ࠷৽ʣ w Ճ͞ΕͨϞδϡʔϧ4FMFOJVNɺLTɺ)JWF.2ͷͭͰ͢
·ͱΊ
5FTUDPOUBJOFSTͷಋೖޮՌ w ࠓհͨ͠ൣғͰ5FTUDPOUBJOFSTͨ͘͞ΜͷࣄΛͯ͠·͢ w σʔλϕʔεͷΠϯετʔϧ͔Βআ·ͰΛςετΫϥεͱີʹ࿈ܞ w ʮ+BWBͱ%PDLFS͕͋ΕͲ͜ͷϚγϯͰޭ͢Δςετʯ͕࡞ΕΔؾ͕͠ ͖ͯ·ͤΜ͔ʁ w গͳ͘ͱΞϓϦςετʹؔͳ͍Ͱɺ։ൃऀͷखΛΘͤΔ࣌ؒ࿑
ྗ࣮֬ʹݮΓ·͢
·ͱΊ w қͱൺֱͯ͠5FTUDPOUBJOFSTͷՌׂͨ͢େ͖͍ͱࢥ͍·͢ w ݸਓతʹຯ͚ͩͲࣄΛ࣮֬ʹ͜ͳͯ͘͠ΕΔࣄਓελΠϧͳͱ͜Ζ͕ ͖Ͱ͢ w ϋϚΓϙΠϯτେମ࣮ߦ͢Δίϯςφͷ༷ɾɾɾ w ࠓճ4QSJOHͱͷΈ߹ΘͤΛհ͠·͕ͨ͠ɺผͷϑϨʔϜϫʔΫʢྫ͑
2VBSLVTʣͱ࿈ܞ͢Δ͜ͱ͕Ͱ͖·͢ w ܁Γฦ͠ʹͳΓ·͕͢ɺςετڥͷ४උͱ͔໘ͳ͜ͱશ෦ 5FTUDPOUBJOFSTʹͤ·͠ΐ͏ʂ w ։ൃऀ͍͍ίʔυΛॻ͘͜ͱʹઐ೦͠Α͏ʂ
ࢀߟࢿྉ w IUUQTXXXUFTUDPOUBJOFSTPSH w ެࣜ)1υΩϡϝϯτ͕ॆ࣮ w (JUIVCͷFYBNQMFʹ༷ʑͳϞδϡʔϧͷαϯϓϧ͋Γ·͢ w IUUQTHJUIVCDPNXFOBTTQSJOHUDFYBNQMF w
ຊηογϣϯͷεϥΠυʹషͬͨίʔυ w શͯΛհͰ͖·ͤΜͰͨ͠ͷͰɺ͠ΑΖ͚͠Εࢀর͍ͯͩ͘͠͞
ίϯςφςετֵ໋ 🐳