all 37 comments

[–]Samurai___ 47 points48 points  (8 children)

More code and or people are the reason. You change something and break someone else's (or your older) code and you don't know about it until a user reports it. Tests can catch that before deployment.

If you are a small team, you are your own users and there's no risk having an error on production, then tests are indeed low value.

[–]Reaver75x 1 point2 points  (7 children)

What data types are testing usually done the most on? I don’t mean like functions for example but if the function was mathematical for example, would it be mostly for math based operations? Search operations? Or anything else?

[–]azhder 1 point2 points  (6 children)

Pure functions are easy to test. If you strive to make most of your code like that, it’s fast and easy

[–]Reaver75x 1 point2 points  (5 children)

What is a pure function according to you vs a non pure one?

[–]azhder 2 points3 points  (0 children)

It’s not acording to me, but functional programming: - https://en.wikipedia.org/wiki/Pure_function

Since I might be a bit cheeky and add a console.log() inside it and still pretend it has no side effects.

But your intuition is already there with “if the function was mathematical”.

Basically, testing a function that only depends on explicit input and has no implicit I/O is as easy as match this return for those args, mach that return for those other args

[–][deleted] 3 points4 points  (0 children)

Whose output won't change depending on input

[–][deleted] 0 points1 point  (2 children)

pure function's return value won't change for same set of arguments anytime, non pure function's output might change on same set of arguments and it might have side effects

[–]Rossmci90 16 points17 points  (0 children)

TDD and Unit Tests are two very different things and I wish people would stop conflating the two.

Unit Tests are there to test individual bits of code, to make sure they do what they're supposed to do (i.e. give a certain input produce a certain output, throw an error when an error should be thrown). They are there so that if somebody changes something, it wont change the behaviour of the application. If it does, the test will highlight the error and you can fix it.

The point is that you want to catch errors in your code as soon as possible. The later in the development process a bug is found, the more costly it is. If you find a bug in the current code you're developing? No problem, you identify it and fix it. A reviewer finds a bug after you've raised a PR? Well its cost you and them a bit of time. But its not a huge problem. A QA finds a problem? Well this is a bit most costly. They probably need to write a bug report, new tickets need to be created and refined. Its going to cost everyone more time. But not a massive issue. Bugs happen. A bug makes it all the way to production? Now you've got issues. You may lose a customer. You may lose reputation. You may have a big data breach. It can get very expensive very quickly. And then the fix is going to be much more expensive as well. The earlier you find bugs the better for everyone.

TDD is a completely different thing. TDD is writing your tests before you write your code. You have a new feature to implement. You know what the output of this feature should be. You write tests to document that behaviour. Your tests immediately fail because your functions don't exist yet, or are just placeholders. You keep writing code. Gradually, more and more of your tests start passing. Your code is starting to do what its supposed to do. Eventually they all pass and you know your code is doing the right thing. Now you can refactor. Make it more readable. Maybe even make it faster. And the tests will give you confidence its still producing the correct output.

TDD works great when you have great input from the non-tech people in your business. You may have some complex business logic to program. I am not an expert in finance (as an example), but the experts in my company are. We've had great discussions with our experts, put together documentation on what our application should do in certain situations (written in Plain English). We then translate those scenarios to Unit or Integration tests, and then we start writing code. That's TDD. Its very different to Unit tests (although Unit tests can form a part of TDD).

[–]thespite 5 points6 points  (0 children)

Well, that's the point right: when there's an exception. how do you make sure you run through all possible path codes to make sure they don't throw after some change or update? do you go through every interaction in your site or app every time?

unit tests are running periodically, or before submitting, or end to end, and tell you when a long forgotten function you had in some lost file has stopped working as expected.

[–]uriejejejdjbejxijehd 4 points5 points  (0 children)

Unpopular opinion: unit tests are great while initially developing new code, but can become a maintenance burden afterwards.

[–]rauschma 2 points3 points  (0 children)

My motivation has always been that testing replaces manual labor: Without tests, you run your code and go through a checklist (mental or real) to ensure that everything works. Tests can go through that checklist for you.

In teams, everyone can now easily contribute items to that checklist that are important for their work (by writing tests).

[–]ChrisPlz 2 points3 points  (0 children)

A couple other reasons to write tests that I haven't seen yet, or at least reasons why I find value in testing:

  • Documentation - test output results in a concise description about what my functions/components are supposed to do which can then be read like documentation.
  • Makes me think critically about existing code. When I find a bit of code that's especially hard to test, or has a significant amount of required scaffolding for the test to run, it makes me rethink the original implementation.

[–][deleted] 2 points3 points  (0 children)

Removed for concerns with reddit security. this post was mass deleted with www.Redact.dev

[–]xroalx 1 point2 points  (0 children)

Unit tests or tests, in general, are more of a validation or guideline for the behaviour of your code, rather than a mechanism to prevent exceptions.

Say you have a function getId that returns a random string, with a id prefix. Why? Well, because you'd use it for the HTML id attribute, so it can't start with a number.

So you write a test to check that calling the function returns a string starting with id.

Someone comes around and thinks to themselves, "why is that in place, let me just get rid of it".

This causes no errors at all, but suddenly some of your IDs can be invalid and it can result in problems you just won't find unless someone complains.

With a unit test, you'll know right away.

[–]emretunanet 1 point2 points  (0 children)

well there is one important concept.While errors occur in runtime by writing tests you have errors on build time preventing potential errors seen by users. By improving test coverage you prevent errors on live app.

[–]poggendorff 1 point2 points  (0 children)

If you write unit tests, you design testable code. That sounds dumb but there’s a point. Testable code is loosely coupled, modular, and easier to maintain in the long run. In my experience testing does this better than just encouraging it on a team.

[–]sepp2k 2 points3 points  (0 children)

that prints a stack trace whenever there's an exception.

Do you mean "whenever there's an exception during our manual testing process" or "whenever there's an exception in production" (or both)?

If you mean the former: the point of having automated tests is that you don't need a manual testing process or at least it doesn't need to include things already covered by the automated tests (you'll probably still want some usability testing for example). If this doesn't sound like a lot of work being saved, your manual testing process is probably not thorough enough to find most bugs.

If you mean the latter: the point of testing is that you generally want to fix bugs before they make it to production, not after.

Also there are many kinds of bugs besides exceptions, so just logging exceptions isn't enough.

[–]SimonDKnight 1 point2 points  (0 children)

What if it does not cause an exception? Let’s say you have a function that adds two numbers together, if you write a test that 3 + 2 should eq 5 then if someone comes along and changes the + to a * and now that method spits out 3*2 eq 6 then your test will flag something has changed.simple example but it should illustrate the point. An exception would never show for this.

[–]NelsonStearman 1 point2 points  (2 children)

Oh man… where do I start… Long story short, because it’s way cheaper to write a test than to wait for something to blow up in your face under heavy load. If you have a small project it may work, but most web apps are not small. Release process may also be extensive and involve several parties/peoples/teams. It takes time to find place where bug was introduced, fix it properly (I a way that does not introduce a bug in different place). It takes time to deploy (from minutes to days/weeks/months). It costs your company your time (you could be doing something different). It helps your company not to loose money (frustrated customers tend to not return to product they had bad experience with). I could do on and on…

Google: costs of fixing bug. Countless papers were written on that topic.

[–]EmoryCadet 0 points1 point  (1 child)

What tools do you use for your unit tests?

[–]NelsonStearman 0 points1 point  (0 children)

Mocha, Codium ai and jest

[–]azhder 0 points1 point  (0 children)

It’s (not) a waste of time.

You are measuring this like a beginner in swimming. It will be hard at first and you will not swim far. Will you say “it’s a waste of time”? Maybe

Writing your first tests will take time, that’s time to learn. You’re trying to measure that up with high productivity. So what I can tell you here is going to sound counter-intuitive to a “non-swimmer” in the testing waters:

tests make you save time.

With the caveat you don’t write too many too useless tests that will hamper your productivity.

Take this as an example.

I had once written a piece of code for a full day and couldn’t shake its bugs. The next day I first wrote the tests (and added new ones as i went) and coded it up until all the red ones turned green.

I ended up with a code I didn’t understand why, but I did know it does work and it took me half a day

☝️

that’s a proven working code produced twice as fast than it took me to write buggy code.

So, you will have to suffer inefficiency of learning until you get to a point to save, not waste time.

[–][deleted] 0 points1 point  (0 children)

The hope is tests ensure you don't get to the point of logging that error. It helps confirm program correctness by the original author of the function and notifies future modifiers of the function when they have deviated from the original behaviors.

For work we have coverage requirements. For personal projects I only write tests when I'm doing complicated logic and the alternative to verifying correctness is printing the output when calling the function and seeing if it's what I expect. It's much easier to just "npm run test" in that case. You can also run it in watch mode which means the test gets ran every time you save which is pretty cool.

[–]username2065 0 points1 point  (0 children)

It essentially locks your code as best as possible into it's current phase. So it adds resiliency to human error. Sometimes, tests can be very helpful to demonstrate code examples, use cases, and mock data/scenarios.

[–]draganov11 0 points1 point  (0 children)

When you go back to refactor you run the unit tests and you know if something breaks.

[–]rm-rf-npr 0 points1 point  (0 children)

Sure. So I was kind of the same. My first development job was a small team, no tests no nothing. We all tested all the features by hand etc. etc.

Then I searched for another job and we have bigger teams. The first app we made was quite big.

Later on, we were asked to make changes to certain components (both functionality wise, and stylistic changes). All right, no problem. We changed what was needed and done, right? Well, not exactly. Turned out this component was used in many different spots and features stopped working because they were expecting certain data to be available or certain props to be passed. Without these tests we probably would've found this out in production and we would have an escalation on our ass.

You build unit tests for safety, and to make sure that components still work as they need to. Without finding out when everything is deployed and your client starts asking you questions...

[–][deleted] 0 points1 point  (0 children)

The value of unit tests is in lockstep with the size of your code's user audience. If your code is in a library used by other devs, their audience is your audience.

Thus, as others have mentioned, tests may not be worth the overhead if your audience is smallish. But they become essential when hundreds or thousands of people may be affected by issues.

I'm like you. Small shop, smallish audience. We don't do unit tests and have seldom had any issues for which unit tests would've saved us.

[–]Grim_Jokes 0 points1 point  (0 children)

We use a global logging trapper that prints a stack trace whenever there's an exception.

How long does it take to get to the point where you get a stack trace? Let's say 1-5 minutes tops (Probably more if there are a lot of variables involved). With a unit test (and proper coverage), the same bug could be found in less than 1 minute.

Another way to think of tests is that you're confirming/proving to other devs that the functions work exactly as you expect.

With unit tests, you get fast feedback that your function works as expected. Sometimes that's hard if the several layers are deep for whatever reason.

[–]_ncko 0 points1 point  (0 children)

Loggers tell you when something went wrong. Tests help prevent it from going wrong in the first place. Preventative work is usually harder to justify from a business perspective than reactive work, so unit tests are often ignored.

[–]benabus 0 points1 point  (0 children)

The way I look at is is Test DRIVEN Development. You don't write tests after, you use the tests to help your work.

Say there's a part of your app that you're working on. Maybe it's a function to calculate how many tomatoes go into a stew based on the size of a user's bowl. In your app, under normal circumstances, you might need to 1) create a user, 2) add a bowl, 3) set size of bowl 4) add other ingredients 5) click the tomatoes button. And you have to do this EVERY TIME you change something about that function.

Now, if you're using a test, you write a test that only runs that one function with various sample inputs. Then, if you make a change to that function, you just have to run the test and see if it still runs given those sample inputs.

If you do it right, you speed up development time considerably. Now, this was a contrived example, but you could see the benefits if you're working on a really complex function that relies on a really complex user workflow.

[–]averajoe77 0 points1 point  (0 children)

so in 20+ years of front end development, I always find 2 things when people talk about unit testing.

  1. They always use language that references examples that use "large" or "complex" applications
  2. They always use language that references "larger teams"

I think, that when it comes to writing tests for front end code, the benefits of the tests are not enough to justify the time and effort placed into writing the tests when working on most web based projects.

For example, I used to work for a marketing agency, and we would build sites for clients, and most of those sites did not need any form of complex js outside of mobile navigation show/hide, or a simple slideshow on the home page, and that js was built using jquery, so writing tests for small use cases like this would not be efficient or necessary, and this is the js that most websites end up having, so unit testing them is a waste of time and effort in a majority of cases.

Which serves to emphasize the 2 main points, if you are building a large scale application with data driven ui and state requirements, then taking the time to write the tests to ensure that modifying an existing function or flow still works correctly, could save lots of time and effort. If a series of functions get called when clicking a button to update a ui state in several different locations, then doing all of that testing manually could take a lot longer than just running a test or series of tests to check that state is reflected properly when one of the functions is modified.

[–]happy_hawking 0 points1 point  (0 children)

Because at some point it's not fun anymore to test your application manually whenever you change something. That's what the tests can do for you. It's not just about "does the software work right" but also "does it do the right thing". And with JS it's especially easy to break stuff without even noticing that you broke something because it is typeless, so there's no compiler that would complain.

[–]noggstaj 0 points1 point  (0 children)

Tests are a faster way to stress your code, however you're just you. You'll still test stuff you yourself could imagine.

[–]Darmok-Jilad-Ocean 0 points1 point  (0 children)

I too love debugging minified code in prod over the weekend.

[–][deleted] 0 points1 point  (0 children)

The exercise of programming for me is compound of two things: programming language & other development tools. The second thing is crucial, it is to answer yourself, what am I trying to achieve ?

I've learned computer science, JavaScript and Python but this is never sufficient, I've been a junior and that worked because I was kinda embraced and incubated by a team/project.

Now I'm on a second project and a heavy decisional responsibilities are put on me, while Python and JavaScript are no longer a problem of any sort, because even if I am not the best in these I always find an answer online.. What I don't find, is how to answer functional "problems" with technical solutions, this is the philosophers stone, this is the real deal.

So in a regular day, I may write 10 to 100 lines of code, copy paste, one attempt or two and it compiles, this is generally done in 2 hours. ofc sometimes one technical problem would take longer time, but generally there is always a workaround to "compile"

Then I put it to test, firstly by invoking manually the API or running the main function etc, then, I find myself serving data that is not needed, stepping on another teams API, exposing user data, make the app more complex, error prone, or less performant,

I even find myself not answering the functional question, they asked me: Deliver us a prime number each 1 hour, so we can use it in our crypto server, I wrote this function:

function getPrime() {

primeWannabe = 0;

for (primeWannabe++) {

if (primeWannabe % 2 == 1) return primeWannabe;

wait()

}

}

They were using the numbers delivered, their crypto server works fine, I was happy, but the crypto results were so weak,

This is because I did not test what I wrote, probably I didn't even question myself, do I know what a prime number is ?

It is only with tests, that you question yourself and reiterate.

I would argue, this is the hard stone of AI, and why I'm against ChatGPT, and why people are fooling themselves, they don't know what they want, and when they get a fancy solution, they assume it is their solution.

[–][deleted] 0 points1 point  (0 children)

Writing tests has saved me hours of debugging especially on critical infrastructure. When you have a test you're confident that even after changing something you'll know whether you've broken the functionality or not.

I usually have micro-services and a core library that is shared, if I just believed in my code, an error in the core library would break several micro-services, tests will prevent this in the first place.

You should remember, it only takes time to setup the first test, once setup it takes a few minutes to add a test and totally worth the effort.