Why Skipping Unit Tests is Like Jumping Out of an Airplane Without a Parachute 🪂
Hey folks! Today, we're diving deep into the world of unit testing. A topic as exciting as a caffeine-induced all-nighter, or as dreadful as a null pointer exception
, depending on how you see it. But jokes aside, it’s essential. 🚀
Why Do We Need Unit Tests Anyway? 🤷♂️
First off, let’s get one thing straight: coding without unit testing is like playing Russian roulette with your project. Sure, you might survive, but is it worth the risk?
Unit tests act as your first line of defense against bugs, allowing you to catch issues early on. Think of it like a spell-checker for your code, continuously validating that your latest commits aren't breaking existing functionality.
In Practice:
Imagine you're building a serverless function in AWS Lambda to calculate the total cost of items in a shopping cart. With unit tests, you can mock various scenarios, ensuring the function handles tax calculations, discounts, and even edge-cases like zero items effectively.
const calculateTotal = require('./calculateTotal');
test('calculates total price', () => {
const cartItems = [
{ item: 'Apple', price: 1.20 },
{ item: 'Banana', price: 0.80 }
];
expect(calculateTotal(cartItems)).toBe(2.00);
});
The Good Stuff: Pros of Unit Testing 🌈
Immediate Feedback: With tools like Jest in a Node.js environment, you get immediate feedback. Anytime you save a file, tests run automatically.
Code Confidence: You get a safety net, making future changes less risky and easier to implement.
Simplified Debugging: When a test fails, you only need to consider the latest changes, making debugging simpler.
Improved Design: Often, the need to make code testable results in better software design.
The Not-So-Good: Cons of Unit Testing 😬
Time Consuming: Writing tests can be time-consuming. However, consider this an investment; the time you spend now will save you debugging time in the long run.
Learning Curve: Setting up your testing environment and learning the syntax can be intimidating, but totally worth it.
False Sense of Security: Passing tests aren’t a 100% guarantee that your code is bug-free. Integration tests and end-to-end tests are essential too.
The Bottom Line 🎯
If you're coding in a professional setting, especially if you're juggling complex systems with AWS and serverless technologies, unit tests aren't optional; they're a must. The initial effort will pay off in terms of maintainability, robustness, and peace of mind.
Some Cool Tools 🛠️
- Jest for Node.js
- Mocha for browser-based code
- Jasmine for those in love with BDD (Behavior-Driven Development)
Round-Off 🌠
That’s it, folks! Happy coding, and may your builds always be green and your coffee cup forever full! ☕🚀
Don’t forget to smash that like button If you found this blog useful and want to learn more, here are some ways you can keep in touch:
- 📩 Email: Drop me a mail
- 🌐 LinkedIn: Connect with Mr. Rahul
- 🏠 Personal Website: Rahul Portfolio
- 🔗 GitHub: Explore my Repos
- 🖋 Medium: Browse my Articles
- 🐦 Twitter: Follow the Journey
- 👨💻 Dev.to: Read my Dev.to Posts
Top comments (18)
I do not think it is intimidating, in total you only need to know 2 methods
Unit test best practice:
About time consuming -> I would argue that you just pay upfront the time you would have spend debugging the same edge cases.
That is hard -> getting typescript tests to work. That is now easily solved by Bun.
I would recommend not testing components, reasons:
Hey there! Thanks for taking the time to share such a detailed perspective! 😄
You've raised a lot of great points. The simplicity of the
test
andexpect
methods is indeed a blessing for those getting into unit testing, particularly with Jest in a Node.js environment. It really helps to keep the cognitive load low.On Writing Logic in Functions
Absolutely agree! Keeping your logic inside pure functions makes it way easier to test. This aligns well with SOLID principles, particularly the Single Responsibility Principle. The more modular your code, the easier it is to test, understand, and maintain.
On Mocking
Your point on mocking is thought-provoking. In a perfect world, we'd minimize the need for mocks, but sometimes with complex systems—especially in a cloud environment like AWS—you might need to mock services to isolate the unit of work. However, I do agree that excessive mocking could slow down the feedback loop and introduce complexity.
On Time Investment
I couldn't agree more. The time spent writing tests can often offset the time you'd otherwise spend debugging. It's all about paying it forward.
On TypeScript Tests
Thanks for the shout-out to Bun for TypeScript testing! It's always good to have easier solutions to complicated problems.
On Component Testing
Interesting viewpoint on skipping component tests. While component tests have their limitations, I feel they still add some value, especially for larger teams and projects. But yes, E2E tests with tools like Playwright can cover a lot of what component tests do, plus give us visual diffs.
I really appreciate the insights you've provided. It definitely adds another layer to the discussion, and I'm sure others will find it valuable too! 🙌
So what are your thoughts on balancing unit tests with integration tests and E2E tests in a CI/CD pipeline, especially when using DevOps tools?
Cheers! 🚀
E2E are integration tests.
No other way can you test integration, E2E-Tests are the only way.
Even with Next.js (Frontend and Backend in one) you still depend on and call external services, db.
If any of your external services (or db) does not behave how you expected it (api changes or anything else) -> your entire app does not work. Examples: db, network, email, payment, not enough resources on the vps, etc.
Testing-Balance
The Balance highly depends on the competence of your devs/team.
E2E as Integration Tests
I couldn't agree more. E2E tests are essentially the ultimate integration tests. They simulate real-world scenarios, making sure that all the cogs in your system mesh perfectly. This is crucial when you're relying on external services or databases; things can break unpredictably when dependencies change, just as you've pointed out.
Testing Balance
Your breakdown on when and how much to test is on point. Prototyping doesn't require exhaustive tests, but the game changes when you're shipping to users.
Unit Tests: You rightly emphasized their importance for capturing the maximum number of edge cases.
E2E Tests: They are resource-heavy but indispensable for primary/common use-cases. Totally agree that their quantity should be proportional to how often the user workflow changes.
Team Competence and Testing
Love this point. The competence level of the dev team plays a huge role in determining the testing strategy. Juniors may require a safety net of extensive testing, while a team of seasoned devs might be able to get by with lighter testing, as they're likely running extensive tests locally.
You summed it up perfectly; it's a balance that's influenced by multiple factors including the competency of the team, the stability of the user workflow, and the nature of your application's dependencies.
In light of your insights, what tools and frameworks do you recommend for optimizing this testing balance, especially when you're in an agile environment where things can change rapidly?
Thanks again for enriching this discussion! 🚀
Hey, thanks for sharing your toolkit! 🛠️
It's great to hear that you're loving Bun's built-in test runner and that it's meeting all your needs after migrating from Jest. That's a significant move and speaks volumes about its capabilities!
Your approach to component testing is super interesting, kind of like a homegrown Storybook. Testing components with actual visual scenarios and mock data is a solid practice, for sure.
As for E2E, Playwright is an excellent choice. It's incredibly powerful for automating browser tasks and conducting visual tests.
Just a heads-up, though: Bun might not be the best fit for everyone, especially those heavily invested in serverless architectures. But for those who can use it, sounds like it's working wonders for you.
Given your extensive experience, do you have any tips on managing test data? How do you usually go about setting up, tearing down, or updating mock data in your tests?
Cheers! 🚀
Since you mention the usage of aws and serverless.
I really like the idea of serverless, but all the ecosystem tools surrounding are not where yet - Its the reason I'm avoiding it. Especially for the reasons you mention
Using local-first
You obviously have a different tech stack.
I do not think I can help you without more Information / examples of how you or others have done it.
I do not have to set-up, tearing down or mock anything in my tech stack.
Hey, thanks for the detailed reply! Your perspective on avoiding serverless for its current ecosystem challenges is understandable. It's definitely an evolving space, and yes, the challenges in testing, debugging, and local development can't be ignored.
On Local Development
Your approach to local-first development is quite smart. Using SQLite for its simplicity and efficiency is an excellent way to maintain speed in your dev cycle. Your point about avoiding cloud-specific databases because they can't be run locally resonates well with the idea of having a seamless dev environment.
Development Feedback Cycle
Couldn't agree more about the importance of a fast development-feedback cycle. It's clear you've optimized for this, given your choice of tools and practices.
Specialized Tools for AWS Mocking
There are indeed specialized tools to mock AWS services, like LocalStack or the Serverless Framework's offline plugins. But I get why you'd prefer a stack that doesn't need such workarounds.
Your comment brings up an important angle on tech stack choices; they really are influenced by what each of us is optimizing for—be it fast feedback cycles, scalability, or something else.
Given your approach, how do you handle scenarios that may require more complex integrations, especially when scaling up? Would love to hear your thoughts!
Thanks for enriching the conversation! 🚀
That kind of integrations?
Internal ones (managed by same company of different teams) or external ones?
Ah, good question! I was thinking more along the lines of external integrations—like third-party services or APIs that you might not be able to run locally. How do you handle those, especially considering your emphasis on local-first development?
Looking forward to your insights! 🚀
Have I missed something?
That's a really neat breakdown of how you handle external integrations! 😎
Auth: Directly creating a test user makes sense for bypassing external auth services during testing.
Email: Rerouting to your own address or using desktop notifications is a solid workaround.
File Storage: Using local file access as a stand-in for S3 or similar services is a pragmatic approach.
PDF Generation: Local PDF generation libraries like Paged.js can indeed mimic the functionality of many external services.
Real-time: Bundling real-time capabilities via websockets directly into Bun shows a well-integrated solution.
You've clearly put thought into how to maintain a fast development-feedback cycle while still enabling complex functionalities. It seems like you've got most bases covered. 💯
Given that you're able to bypass or mock most external dependencies for local development, do you ever find that this approach leads to discrepancies when you deploy to a real-world environment?
Cheers! 🚀
I agree with you to some extent, even though it is a bit extreme.
However, I am disappointed that vitest is not included in the recommended test libraries.
Hi @artxe2 Firstly, I appreciate you taking the time to read the article and sharing your perspective. I agree that everyone has their own experiences and preferences when it comes to development practices.
Regarding vitest, you're absolutely right! It's indeed a valuable testing library, and I'm grateful you brought it to my attention. I focused on some of the more widely known libraries in the article, but I acknowledge that there are many fantastic tools out there, including vitest. I'll definitely consider diving deeper into it and perhaps even feature it in a future piece. Your feedback helps in making the content better and more inclusive for everyone. Thanks again! 🙌
Warm regards,
Mr. Rahul
Hi Rahul,
I very much agree with your post. I think Unit test is actually less about testing and more about proving developer intent. That is why I wrote a post on this theme. I hope you get chance to read it and please give me your thoughts.
I heard it said, "If your are refactoring code without unit tests your are not refactoring, you are just changing code" and IMO you get what you deserve!
Regards, Tracy
Hi @tracygjg ,
Thank you for your comment! It's always gratifying to meet someone who shares similar viewpoints. I completely agree—unit tests indeed go beyond just "testing"; they're about affirming that the code does what it's intended to do.
Best regards,
Mr. Rahul
Your source code is really good.
Unsung? Seriously?
Some comments have been hidden by the post's author - find out more