-
Notifications
You must be signed in to change notification settings - Fork 2.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
How do you write testable code? #189
Comments
@MartinMuzatko Great idea although I'm not a fan of making big changes to code only for the sake of testing. That said, there are unnecessary things that can greatly complicate the testing experience:
Agree with what you wrote except with DI/configurable code. I don't like to change my code for testing, not to say sacrifice encapsulation. I prefer monkey-patching. |
One more point from today:
|
I love the new bullet points :) I think especially important is the module singletons problem. But I wouldn't limit it to singletons. I would go as far as to ban any side effects in the top level of the code, unless they are an application entrypoint. But yeah, singletons are definitly the core of the problem. Top-Level Code should be free from side-effects Your module should
That makes modules more portable and usage intuitive and enables to build on top predictably. |
Great observations. I guess by top-level you mean to import/require Now I'm faced with something beyond that - When my logger.info is called, it sets locally a default configuration (no reason to set config state in every call, also we can't assume that someone will call logger.configure before the 1st call). Now my 1st test pass, but my 2nd can't simulate a scenario because the configuration is already set |
Adding one more to the list - Never relate to fixed port rather makes it configurable. Test can pass "0" and get an emepheral port. Otherwise, parallelizing tests won't be possible |
One more - Exporting objects with functions is easier to mock that exporting just functions. I don't suggest that one should change her coding style, only to be aware that 'conventional' lib like sinon/test-doubles act on an object level |
One good practice I like is that each test should explicitly state (via comment or otherwise) who the user is. Every test should be written with a user in mind. Unit tests often the users are other engineers on your team. If you communicate this and tag these tests as such it becomes much easier to define best practices for each type of test and evolve them as rewrites occur. |
@palmerj3 That is surely interesting, can you provide an example for test name/comment? Is this related with 'testable code' or a general testing best practices (which is the right place to share!)? |
A simple docblock at the top of each test will suffice. We hear often about having a healthy split between unit, integration, e2e and other. But usually this split can't be measured unless we use different test runners or completely different suites for each type. This gives you some ability to measure this and set standards. So you can analyze your distribution and set standards for each type. So this is not a best practice but something that enables you to have effective best practices enforced. |
That's tricky. What are the options? Maybe with types you can ensure that only a configured instance of the logger gets used. |
Not sure if that is out of the scope of this best practice guide. I, however, miss an integral part that explains how to write code that is easier to test in the first place.
That is only explained on the side in point 1.13 - other generic testing hygiene. This could be split into two or three points that specificially focus on the do's and don'ts to enable testing and how to structure such code.
This is my subjective view or recommendation I would put into the list:
Bad examples:
Good examples:
In my experience, that goes hand in hand with benefits like more readable code, configurable behavior and options, focused functions. Some recommendation how to structure code or functions in a way that enables testing in the first place would be great.
What do you think?
The text was updated successfully, but these errors were encountered: