Kent C. Dodds入門
フロントエンドのテストについての記事を読むスクラップ
追記:最初は「テスト設計/戦略みたいなものを考えられる人間になりたい」というでやっていたが、結果的にKent C. Dodds入門になりました
You can throw paint against the wall and eventually you might get most of the wall, but until you go up to the wall with a brush, you'll never get the corners. 🖌️
testing trophyはテストのROIに着目した概念らしい
- End to End: A helper robot that behaves like a user to click around the app and verify that it functions correctly. Sometimes called "functional testing" or e2e.
- Integration: Verify that several units work together in harmony.
- Unit: Verify that individual, isolated parts work as expected.
- Static: Catch typos and type errors as you write the code.
The idea behind integration tests is to mock as little as possible. I pretty much only mock:
- Network requests (using MSW)
- Components responsible for animation (because who wants to wait for that in your tests?)
The biggest and most important reason that I write tests is CONFIDENCE. I want to be confident that the code I'm writing for the future won't break the app that I have running in production today. So whatever I do, I want to make sure that the kinds of tests I write bring me the most confidence possible and I need to be cognizant of the trade-offs I'm making when testing.
トレードオフ
トロフィーの上に行けば行くほど
- コストがかかる(テストの記述に要する時間が長くなる上に、対象範囲が広い方がテストが通りにくくなるため)
- 実行速度が遅くなる
- 信頼性が高まる
What I'm interested in is whether I'm confident that when I ship my changes, my code satisfies the business requirements and I'll use a mix of the different testing strategies to accomplish that goal.
原理原則を見つけた
Eventually, I created Testing Library to encourage the kinds of testing practices that worked best for me:
Testing Libraryの思想を深堀りすればこの人の考えは理解できそう
と思ったら思想紹介記事がリストアップされていた。これ読んでくか。
Confidently Shipping Code: Why I care about testing.
Static vs Unit vs Integration vs E2E Testing for Frontend Apps: What these mean, why they matter, and why they don't. ⭐️ This one has code examples you might find instructive if you'd like more concrete examples of how I think about these different classifications of tests.
Testing Implementation Details: Testing implementation details is a recipe for disaster. Why is that? And what does it even mean?
Avoid the Test User: How your UI code has only two users, but the wrong tests can add a third.
Should I write a test or fix a bug: How to prioritize tests relative to everything else.
How to know what to test: Practical advice to help you determine what to test.
Implementation detailsなるものをテストすると、リファクタ時に偽陽性・偽陰性が生まれやすいので避けよう。代わりに、入力に対して適切な出力があるかをテストしよう。という考え方。
Implementation detailsは正確にはこう定義されていた
Implementation details are things which users of your code will not typically use, see, or even know about.
End-users and developers are the two "users" that our application code needs to consider.
ここでもなんとなく関数コンポーネントのメンタルモデルというか冪等性という概念が重要であることがにおってくる
Testing Libraryの思想
Implementation detail free and refactor friendly.
- What part of your untested codebase would be really bad if it broke? (The checkout process)
- Try to narrow it down to a unit or a few units of code (When clicking the "checkout" button a request with the cart items is sent to /checkout)
- Look at that code and consider who the "users" are (The developer rendering the checkout form, the end user clicking on the button)
- Write down a list of instructions for that user to manually test that code to make sure it's not broken. (render the form with some fake data in the cart, click the checkout button, ensure the mocked /checkout API was called with the right data, respond with a fake successful response, make sure the success message is displayed).
- Turn that list of instructions into an automated test.
テストもユーザードリブンでやればよいことがわかった。
仕様書としてのテスト、TDDみたいな考えへの理解も深めたい。
The more your tests resemble the way your software is used, the more confidence they can give you.
ここがこの文章のタイトルの意味だった
But as soon as you start testing things which your developer user and end user don't know or care about (implementation details), you add a third testing user, you're now having to keep that third user in your head and make sure you account for changes that affect the testing user as well.
testかbug fixかという区別にはあまり意味がなくて、それがどれくらい大切なことなのか?を考える必要がある。
ユーザーのbioを変更できないバグよりも、購買フローにテストが書かれていないことのほうが深刻
簡単なスクリプトにテストが書かれていないことよりも、プロダクトが十分に売れていないことのほうが深刻
We write tests to be confident that our application will work when the user uses them
Think less about the code you are testing and more about the use cases that code supports.
テストを書く時にはuse caseに着目しろ
Code coverage is not a perfect metric, but it can be a useful tool in identifying what parts of our codebase are missing "use case coverage".
Test use cases, not code.
TDDもたぶんこういう発想だと思うんだけど、じゃあどうやってユースケースカバレッジ100%を保証するかって話になるよな。演繹的に導けるもんなのか、ある程度経験則が補うものなのか。
What part of this app would make me most upset if it were broken?
100%保証みたいな考え方はそもそも馬鹿げていて、優先度の高いところから地道に潰していくしか無いということかな
Once you have that prioritized list, then I suggest writing a single end to end (E2E) test to cover the "happy path" that most of your users go through for the particular use case. Often you can cover parts of several of the top features on your list this way. This may take a little while to get set up, but it'll give you a HUGE bang for your buck.
Once you have a few E2E tests in place, then you can start looking at writing some integration tests for some of the edge cases that you are missing in your E2E tests and unit tests for the more complex business logic that those features are using. From here it just becomes a matter of adding tests over time. Just don't bother with targeting a 100% code coverage report, it's not worth the time.
本質ぅ〜!