Hey everybody!
I was wondering lately when I should start writing tests?
Usually there are some common approaches like TDD which I heavily disagree with as it consumes a huge amount of time. Not because of writing the tests but because of future refactorings while the application is not released yet.
So I thought about writing the tests "at the end", when all the functionality is ready for deployment and for public use (of course there will never be an "end").
What are your approaches? Do you write e2e and integration tests? Which stack do you use?
EDIT: Thanks to everyone for such valuable feedback on this topic! It really helps me out!
When the cost of not testing is greater than the time + opportunity cost of writing tests.
Bingo! I've found this is usually around the time I start looking to gather feedback from my first users and need to be able to quickly add new features without worrying about blowing everything up.
Opportunity cost?
This is the correct answer! What is the biggest risk to your business? If you're still validating an idea, thenunit tests are not reducing any risk. However if you have customers that rely on your service everyday, then unit tests can help reduce the possibility of downtime and lost customers.
👍👍
There are already many good general answers here, so I want to make you aware of something specific. Having good tests will actually help you refactor your application! They should be higher level and focussed on the customer side. Then you can change the underlying logic without breaking anything.
As with everything, TDD should not be applied blindly. However, developers often underestimate their ability to write bug free code and tests usually turn out to be more useful then you thought initially.
In your case I would write some higher-level tests during the development to guard you from breaking important behavior. I would not focus on getting a high line coverage or some other similar metric.
I totally get the resistance towards TDD, and in my opinion it's usually not the right approach, since it assumes you know all the specs, features and technical implementation up front. When we're working agile, or with MVPs, that target is constantly shifting during the development phase.
I don't believe in TDD, but I am a strong supporter of writing tests early. I believe they improve code and save you time down the line.
My approach is to spend time just figuring out what I want to build, and how to build it. The code doesn't have to be refined (yet), as long as it does the job. As soon as I have a pretty good idea of the what and the how, I start writing tests.
Just like the initial code, these tests might not be very refined either. They're usually hastily thrown together, simply to act as a security net when I add more features or refine the code I've already written. That way, if I decide to change the approach, I can simply change the tests as well.
As I become more certain in my implementation, I will improve the code and finalise the tests. This is also where I might spend more time on some edge cases I didn't bother with earlier.
I know some people are against testing – personally, I believe that comes from a lack of understanding. Testing takes time, that is very true, but it should be considered an investment. Time spent writing solid code with solid tests means less time spent on fixing bugs and refactoring code further down the line. Which means, a more stable product, happier users and a happier you.
TDD doesn't determine architecture or require you to know all the tech specs. But of course you know the technical implementation, you're writing the code aren't you?
I follow a strict mindset with TDD. If you're already invested enough to be writing code for your product instead of using a no code solution, you can do so with TDD.
This is more of a style choice. But your code will never be as modular as tested as it could have been, if you originally started with tests.
I might have a general idea, but I prefer to test that thesis before I commit to it by writing the tests. By writing the tests first, you will "lock in" your solution, and it will be harder to pivot if you discover a better approach during development.
I strongly disagree. TDD is not a strict requirement for modularity in your code.
However, I think we agree that writing tests early will improve the final product. You learn to think about the code in a more structured way, and your tests might uncover edge cases or code smells you wouldn't otherwise think of.
When it comes to shipping good code quickly, it is my belief that testing early and testing thoroughly is the way to go. But I'm not a believer in TDD.
I honestly was always against testing because I was reluctant to learn how to do it and felt that it just took time away from actually developing. But now I have implemented it for parts of my project and the difference it makes is just crazy. There have been bugs I chased for months and only ever really got to the bottom of once I started implementing tests. The time it saves for each new feature development is as well huge. I can be certain that what matters most still works. So you are right that it certainly makes no sense to start testing too early, but once you have a MVP that real users use I would work on getting the most crucial parts automatically tested so that you can keep publishing new features feeling confident that nothing is broken.
I don’t think you need to take the all or nothing approach. Do it the indie hacker way. Don’t try to cover everything and every obscure use case. Just what matters right now to ship a better product.
A good thing is as well just fixing bugs whenever they come in and then writing a test to make sure it doesn’t happen again.
I had the exact same mindset about testing! But now that I am creating an actual product for the public to use, I have some anxiety about some things that I didn't test manually just don't work properly. That's why I wanted to know how other indie hackers approach testing. Basically just so I can sleep better and have happier customers. Thanks for your input 🙏
Tests are a trade-off and only you know what tests are useful for your app, at the current stage of your app. This includes having no tests (i.e. manual testing).
A lot of good points were already mentioned here. I'll add some random thoughts from experience:
In my opinion, you should write at least one test on almost day 1. For one, this ensures that when you do hit that point where you definitely need to write tests, you don't have the obstacle of "how do we write our first test?". For another, I find tests give me a good playground to experiment with the app without needing to create the whole thing. I can start experimenting with logic without needing to setup the http stack, for example.
I'll often write a test like
Then, I'll run jest in watch mode and I can see the output as I iterate on the code. I won't ever commit that test, but it'll inform me of what tests are useful once the code is ready.
There's also a question of "when is it appropriate to write what kind of tests".
If your app requires user login, you should probably write a UI automation (selenium, cypress, etc) test that proves login works pretty early on. Typically, those tests can be generalized so they can go pretty much unchanged as the app evolves. This should be one of the few UI automation tests you ever need to write (UI automation tests have a lot of moving parts and external dependencies. If you write more than a handful of them, the math pretty much guarantees you'll never have a passing build).
You probably don't need to go for high unit coverage early on if testing isn't your thing, but if there is a gnarly bit of logic where you know how you want it to work and you're not sure how to make it work, it's nice to be able to TDD that one file.
PollyJS or nock are two handy tools where you can avoid some of the difficulties of writing unit tests by writing, effectively, an integration test, but record the network parts so when the tests run, you never hit the network.
I love TDD, but I almost exclusively write E2E tests - that is, I test only the API. I build my tests as I build the API, because I know what I'll be sending to the API and what I should be expecting back. It's rare that that interface changes too much, so these tests are relatively "safe" to write early.
Plus, they give you an incredible harness when you want to do a major refactoring inside your code. I've performed refactorings that modified many dozens of files, and I had the confidence to do them because I could run my API tests afterwards and know that the same requests produced the same output (and updated the DB in the same way, sent the same emails, communicated with the same 3rd-party services, etc).
As for stack, I'm writing a SaaS starter kit entirely in JavaScript, so I use Jest for my test stack. However, I have a lot of helper functions I've put together to ensure that authentication, form validation, etc. is very easy to test and takes only a few lines of code. If you don't already have such helper libraries with what you're using, write them. The time saved by having them around will repay you many times over.
There is a place for all types of tests, Unit, Integration, E2E, Performance etc. (see the test pyramid: https://martinfowler.com/bliki/TestPyramid.html) it really depends. I don't know that I would say TDD is a problem when you are refactoring since even though you may be refactoring in one area, the other areas that you are not touching still need coverage.
Another sometimes hidden benefit of TDD is that you write the minimum code to get your requirement met and no more i.e. no "gold plating" or "crystal balling".
That said, if you really want to do as little writing tests as possible but get at least get a few hours sleep at night! I would start with E2E tests in something like Cypress, especially if you are using javascript frameworks as it's very simple to get started and write tests. At least you will know that your main workflows/features are functioning.
These E2E tests are invaluable when you start to refactor because you can change everything and still guarantee that the site still delivers the main features you are selling.
Also agree with @jaschaio regarding writing tests to cover bugs that arise so they don't happen again.
Tests are not arbitrary stuff so you flex on others like "yeah my app is fully TDD'd". They serve a specific purpose and most of the time that purpose is to have confidence that your app works as expected and that you won't need to test stuff manually.
It is true that writing tests take time, but it is not wasted time. You will benefit it right after you have more than one page/feature/API to test. Tests give you the opportunity to make sure everything works in one command. You won't be filling that one form in 100 different ways to make sure it behaves correctly, your tests will do that in a few seconds for you. That's a big benefit.
POSTrequest to a page and checking the response HTML for a specific error/success message.TL;DR: Make sure when an actual user interacts with your app, they won't be frustrated with its behaviours.As I said, I really disagree with TDD as it consumes more time when changing methods or functionality. The only reason I want to test is to sleep better. Starting with important user interactions and with feature tests seems like a good strategy for me. Thanks for pointing me to that approach 🙌🏽
Hi! We're not using a lot of tests but when we create them they have a precise purpose. For example, we apply tests on functions that must not fail and that someone can change through time. For example validations in form fields
Some great comments here already on when/why to test. Figured I'd these two thoughts/ideas.
---
I was running a startup that had to layoff most of the engineers so we could become profitable as a lean business -- needed to sell the company to private equity. In doing so, there were just two engis left and 60 customers. We were in a shared incubator space, and one of the other founders of a different company in the space asked me how I operated the business with just 2 engis for all my customers. His engineers were DROWNING in support. My answer was simple, tests. We have amazing tests. Their org did not, they just cranked out untested code for 2 years and it was now all on fire.
Lastly, code shaping. I recently had a service built with no tests, mainly because testing was going to be hard and we just needed something shipped. Big mistake. Cost us 6 months to go back and rebuild the entire thing. Told myself never again. Tests should be built with the code, don't need to be strict TDD, but there should be tests written and a conversation about how/why the trade-offs these tests represent. Because all implementations are a set of trade-offs.
My approach for MVPs and quick projects is simple.
I write tests that helps me test my application. I choose the classes or APIs I will test based on the confidence and complexity of the code.
With a small set of test you can cover more than 80-90% of the bugs.
If TDD makes it harder for you to refactor, then you are testing implementation details instead of behavior.
If you use TDD to only do behavorial tests, then it will never block you. It will save you from having to manually open your app and tap around every time you make a code change, and the tests will only break, when you break behavior.
I always do TDD. It saves me a lot of time, even when I knowingly break behavior. If a behavior test fails because the spec i changed, I just delete it.
Write the unit tests. TDD should be a practice you pick up, so that writing tests isn't a question. It's how you code.
I've seen writing tests take longer because your initial idea of what the code should look like isn't modular. TDD exposes that. It saves you from discovering the mistakes later on when you need to reuse your code in an expected way.
TDD will help you reuse your code for the unexpected changes startups experience.
I can tell you something about writing tests. I have worked in two companies - company1 codebases with 0 tests for around 1.5 years and around 2 years with company2 codebases which had tests and coverage around or more than 80%.
Coming to the stack, mostly I have used Ruby, rails, RSpec (writing tests in this stack is lot fun) and Nodejs with mocha chai. I have also written infrastructure specs using Chef Inspec.
When to write:
I would prefer to write tests right from the beginning but that is no easy to maintain. I often end up implementing something which forms a skeleton and then write specs around it. But that is early into development. If I think of writing specs at the end, I often end up not writing at all. This is mostly because your application is done for now and writing tests for whole application becomes a daunting task.
This comment has been voted down. Click to show.
This comment was deleted 5 years ago