Update unit test naming guidelines#134
Conversation
de1d430 to
d4bb6cb
Compare
There was a problem hiding this comment.
Pull Request Overview
This PR updates our unit test naming guidelines to improve clarity and maintainability of our test suite.
- Added a structured set of instructions for naming tests using active verbs.
- Included new examples of both poor ("Don't") and good ("Do") naming practices.
- Provided an extended list of considerations to ensure test names are descriptive and concise.
Comments suppressed due to low confidence (1)
docs/testing/unit-testing.md:125
- [nitpick] The test name in this example includes the 'should' prefix even though the guidelines recommend avoiding it. Consider revising the test name to remove the 'should' prefix and focus directly on the behavior.
it('should successfully add token when address is valid and decimals are set and symbol exists', () => {
avoid confusion as when I asked to use the 3rd person form for verb, this doesn't apply to "render" in "render matches snapshot" as render is not the verb here but a noun. The verb is match which is correct here as "matches". So they replaced the correct phrase by "renders matches snapshot" which is wrong. Remove render to avoid verb/noun confusion and anyway, render is obvious and part of the test implementation
…ions - Break up test naming examples into pairs with explanations - Add example for missing/unclear test descriptions - Clarify error-related test naming (be specific about error types) - Update snapshot test naming to 'matches rendered snapshot' - Remove vague terms like 'gracefully' and 'handles' from examples - Enhance guidance to avoid weasel words and subjective language
There was a problem hiding this comment.
Sorry this has been open for so long, I just realized I already reviewed this a while back but I forgot about this 🤦🏻
Thank you for this! As the original author of this guide, I fully admit I have a habit of using too many words. So I appreciate these changes. I had some comments/suggestions below, but they are all minor.
Co-authored-by: Elliot Winkler <elliot.winkler@gmail.com>
Co-authored-by: Elliot Winkler <elliot.winkler@gmail.com>
Co-authored-by: Elliot Winkler <elliot.winkler@gmail.com>
Co-authored-by: Elliot Winkler <elliot.winkler@gmail.com>
mcmire
left a comment
There was a problem hiding this comment.
Thanks for the discussion @NicolasMassart. Again I appreciate your attempts to make this more understandable and thanks for your patience. I think we are close on this.
| ## Keep tests isolated | ||
|
|
||
| A test must pass whether it is run individually or whether it is run alongside other tests (in any order). | ||
| A test must pass when running alone or with other tests (in any order). |
There was a problem hiding this comment.
"a test ... when running alone" sounds like the test is running itself, hence the suggestion.
I see what you mean about "whether". What do you think about this instead:
| A test must pass when running alone or with other tests (in any order). | |
| A test must always pass. Running a test by itself or with a group of other tests must not change the result. |
| Tests must run in a clean environment. If a test changes any part of the environment, it must undo those changes before finishing. This prevents the test from affecting other tests. | ||
|
|
||
| Here are ways to do this: | ||
| Ways to keep tests isolated: |
There was a problem hiding this comment.
Okay, good callout. Perhaps we could stick a "The" at the front then?
| Ways to keep tests isolated: | |
| The next sections suggest ways to keep tests isolated. |
| Global variables are properties of the global context (usually `global`). Changes to these variables affect every test in a test file. | ||
|
|
||
| If the global you want to change is a function, it is best to mock the function using `jest.spyOn` so that it is easy to undo it later (note: this guideline is best paired with the above guideline so that you can make this happen automatically): | ||
| If the global is a function, mock it using `jest.spyOn`. This makes it easy to undo later. (Combine this with the previous guideline to handle it automatically.) |
There was a problem hiding this comment.
To provide more details on this suggestion:
- It seems that we are telling the reader about a concept and then directing them to follow some instructions. As a reader the transition was not as smooth as I had hoped. By using the word "you" I thought this paragraph flowed a bit more smoothly with the previous one.
- We say "this makes it easy to undo later", but is the "it" in this sentence meant to refer to the mock function created or the global? My thought is that the thing we are undoing is the mock function. But if you disagree (or the wording you suggested is understandable well enough) we can keep the language as-is.
- I don't expect people to read this section all the way through so I thought we could remove "(Combine this with...)".
| ``` | ||
|
|
||
| Now say the global you want to change is not a function: | ||
| If the global is not a function: |
There was a problem hiding this comment.
I made this suggestion because I wanted to start this sentence with "If you want to..." in order to match the suggestion I made above. It also felt like we were missing instructions for the reader.
| **Do not test private code directly.** Instead, test the public methods that call the private code. Write tests as if the private code is part of the public method. | ||
|
|
||
| Test code marked as private as though it were directly part of the public interface where it is executed. For instance, although you might write the following: | ||
| For example, you might write this code: |
There was a problem hiding this comment.
I made this suggestion because it pairs with the next suggestion. Together it says:
"Take this code for example: . This code behaves exactly the same as though ..."
But if you see these sentences as separate, here is another attempt:
| For example, you might write this code: | |
| The following example defines a couple of private methods: |
| ``` | ||
|
|
||
| this is what consumers see: | ||
| Consumers (and your tests) can only see the public interface, which behaves as if the private methods were inlined: |
There was a problem hiding this comment.
I made this suggestion to pair with the previous suggestion (I am assuming that the reader has read the example above). But if you don't like the use of "this" (which I admit could be ambiguous), or if you think this sentence should stand alone, then here is another attempt:
| Consumers (and your tests) can only see the public interface, which behaves as if the private methods were inlined: | |
| Since consumers (and tests) can only see the public interface, the example above behaves as if private methods and properties were inlined: |
| ``` | ||
|
|
||
| and as a result, this is how the method ought to be tested: | ||
| Therefore, test the public `stop` method by verifying all the behaviors that result from calling it, including the effects of the private methods: |
There was a problem hiding this comment.
Another attempt, which is simpler:
| Therefore, test the public `stop` method by verifying all the behaviors that result from calling it, including the effects of the private methods: | |
| A test suite for this class might look like the following: |
| ### Restore function mocks after each test | ||
|
|
||
| Set Jest's [`resetMocks`](https://jestjs.io/docs/configuration#resetmocks-boolean) and [`restoreMocks`](https://jestjs.io/docs/configuration#restoremocks-boolean) configuration options to `true`. This instructs Jest to reset the state of all mock functions and return them to their original implementations after each test. (This option is set in MetaMask's [module template](https://github.com/MetaMask/metamask-module-template).) | ||
| Set Jest's [`resetMocks`](https://jestjs.io/docs/configuration#resetmocks-boolean) and [`restoreMocks`](https://jestjs.io/docs/configuration#restoremocks-boolean) configuration options to `true`. Jest will then reset all mock functions and return them to their original implementations after each test. (MetaMask's [module template](https://github.com/MetaMask/metamask-module-template) includes this setting.) |
There was a problem hiding this comment.
I made this suggestion because I thought it was shorter. I also thought we didn't need to mention the module template; it is enough to follow these instructions.
- Refine descriptions for grouping tests and specifying behavior - Emphasize the importance of concise and clear test descriptions - Add new guidelines to avoid filler words, vague descriptions, and implementation details - Clarify the approach to testing private code and maintaining test isolation
mcmire
left a comment
There was a problem hiding this comment.
Thanks for the changes! LGTM.
Test Naming Guidelines Update
Updates our test naming conventions to improve clarity and maintainability of our test suite.
Key Changes
Note
Low Risk
Documentation-only changes to contributor guidelines; no runtime, security, or application code is affected.
Overview
Updates
docs/testing/unit-testing.mdwith clearer, more prescriptive guidance on how to name and structure unit tests, plus editorial tightening across the rest of the page.The
itdescription section is the main addition: eight numbered rules (present-tense verbs, outcome-focused wording, no filler like "should", avoid implementation details, etc.) and many new 🚫/✅ example pairs (tokens, redirects, errors, vague names). Snapshot tests now recommend names likematches rendered snapshotinstead ofshould renders correctly, with complete example blocks.Other sections are largely reworded for brevity (Jest intro,
describegrouping, four-phase tests, isolation,beforeEachvs helpers, mocks, snapshots). Minor structural tweaks include bullet lists for private-code types, dropping the 💡 prefix on one heading, and removing one "Read more" link under test-as-specification.Reviewed by Cursor Bugbot for commit dfdcb07. Bugbot is set up for automated code reviews on this repo. Configure here.