this post was submitted on 02 Nov 2023
1294 points (98.4% liked)

Programmer Humor

32410 readers
1 users here now

Post funny things about programming here! (Or just rant about your favourite programming language.)

Rules:

founded 5 years ago
MODERATORS
 
top 50 comments
sorted by: hot top controversial new old
[–] AAA@feddit.de 87 points 2 years ago (5 children)
[–] BustlingChungus@lemmy.world 42 points 2 years ago

The Testmen?

[–] dan@upvote.au 11 points 2 years ago (1 children)

I've written some tests that got complex enough that I also wrote tests for the logic within the tests.

[–] AAA@feddit.de 7 points 2 years ago

We do that for some of the more complex business logic. We wrote libraries, which are used by our tests, and we wrote tests which test the library functions to ensure they provide correct results.

What always worries me is that WE came up with that. It wasn't some higher up, or business unit, or anything. Only because we cared to do our job correctly. If we didn't - nobody would. Nobody is watching the testers (in my experience).

[–] kevincox@lemmy.ml 6 points 2 years ago (1 children)

Mutation testing is quite cool. Basically it analyzes you code and makes changes that should break something. For example if you have if (foo) { ... } it will remove the branch or make the branch run every time. It then runs your tests and sees if anything fails. If the tests don't fail then either you should add another test, or that code was truly dead and should be removed.

Of course this has lots of "false positives". For example you may be checking if an allocation succeeded and don't need to test if every possible allocation in your code fails, you trust that you can write if (!mem) abort() correctly.

[–] Lifter@discuss.tchncs.de 1 points 2 years ago

Right,too much coverage is also a bad thing. It leads to having to work on the silly tests every time you change som implementation detail.

Good tests let the insides of the unit change without breaking, as long as the behave the same to the outside world.

[–] Kidplayer_666@lemm.ee 5 points 2 years ago

Create tests to test the tests. Create tests to test those. Recurse to infinity

[–] dopeshark@lemmy.world 3 points 2 years ago (1 children)

Who tests the tests for the tests

[–] AAA@feddit.de 3 points 2 years ago

Unfortunately, if anyone, I do.

[–] Alexc@lemmings.world 55 points 2 years ago (1 children)

This is why you write the test before the code. You write the test to make sure something fails, then you write the code to make it pass. Then you repeat this until all your behaviors are captured in code. It’s called TDD

But, full marks for writing tests in the first place

[–] oce@jlai.lu 67 points 2 years ago (6 children)

That supposes to have a clear idea of what you're going to code. Otherwise, it's a lot of time wasted to constantly rewrite both the code and tests as you better understand how you're going to solve the task while trying. I guess it works for very narrowed tasks rather than opened problems.

[–] moriquende@lemmy.world 27 points 2 years ago (1 children)

100%. TDD is just not practicably applicable to a lot of scenarios and I wish evangelists were clearer on that detail.

[–] ChickenLadyLovesLife@lemmy.world 18 points 2 years ago

You could replace "TDD" with pretty much any fixed methodology and be completely accurate.

[–] time_fo_that@lemmy.world 16 points 2 years ago

This is the reason I dislike TDD.

[–] ChickenLadyLovesLife@lemmy.world 13 points 2 years ago

The only projects I've ever found interesting in my career was the stuff where nobody had any idea yet how the problem was going to be handled, and you're right that starting with tests is not even possible in this scenario (prototyping is what's really important). Whenever I've written yet another text/email/calling/video Skype clone for yet another cable company, it's possible to start with tests because you already know everything that's going into it.

[–] homoludens@feddit.de 13 points 2 years ago* (last edited 2 years ago)

constantly rewrite both the code and tests as you better understand how you’re going to solve the task while trying

The tests should be decoupled from the "how" though. It's obviously not possible to completely decouple them, but if you're "constantly" rewriting, something is going wrong.

Brilliant talk on that topic (with slight audio problems): https://www.youtube.com/watch?v=EZ05e7EMOLM

[–] nic2555@lemmy.world 4 points 2 years ago (1 children)

TDD doesn't imply that you write all the tests first. It just mean you have to write a test before you write a line of production code.

The idea is to ask yourself "what is the first step I need, where am I going to begin?". You then write a test that validate this first step and fail. Then you write the code to make it pass. Once your done with that, you ask yourself: "what's the next step? ". You, then, repeat the process for that step.

This is a process you are going to do anyway. Might as well take the time to write some test along with it.

[–] Lifter@discuss.tchncs.de 3 points 2 years ago

That leads to focusing on the nitty gritty details first, building a library of thing you think you might need and you forget to think about the whole solution.

If you come up with another solution half way through, you will probably throw away half of the code you already built.

I see TDD as going depth first whereas I prefer to go breadth first. Try out a solution and skip the details (by mocking or assuming things). Once you have settled on the right solution you can fill in the details.

[–] Alexc@lemmings.world 4 points 2 years ago

The tests help you discover what needs to be written, too. Honestly, I can’t imagine starting to write code unless I have at least a rough concept of what to write.

Maybe I’m being judgemental (I don’t mean to be) but what I am trying to say is that, in my experience, writing tests as you code has usually lead to the best outcomes and often the fastest delivery times.

[–] cupcakezealot@lemmy.blahaj.zone 14 points 2 years ago (3 children)

turned out to be a semicolon

[–] Zaphod@discuss.tchncs.de 23 points 2 years ago (1 children)

The tests wouldn't even run of that was the issue, pretty sure (depends on the language I suppose)

[–] gratux@lemmy.blahaj.zone 13 points 2 years ago (1 children)

fun situations can arise when you write , instead of ; For those not in the know, in c++ the comma operator evaluates the left expression, discards the value, then evaluates the right expression and returns the value. if you now have a a situation like this

int i = 0,
printf("some message");

i has a completely different value, since it actually uses the return value of printf instead

[–] scubbo@lemmy.ml 4 points 2 years ago

And people give Python shit for significant whitespace 😂

[–] rwhitisissle@lemmy.ml 4 points 2 years ago

And in python, no less. Sloppy.

[–] rob64@startrek.website 4 points 2 years ago (1 children)

I'll just write thousands of lines of code inside a global object... I'm sure I won't put a semicolon where a comma should be...

[–] Speculater@lemmy.world 1 points 2 years ago* (last edited 2 years ago)

Easy solution:

Find all: ;

Replace with: ,

[–] ICastFist@programming.dev 11 points 2 years ago

I remember being asked to make unit tests. I wasn't the programmer and for the better part of a week, they didn't even let me look at the code. Yeah, I can make some great unit tests that'll never fail without access to the stuff I'm supposed to test. /s

[–] fmstrat@lemmy.nowsci.com 11 points 2 years ago

But this does mean, writing tests works.

[–] fiveoar@lemmy.dbzer0.com 8 points 2 years ago (1 children)

Contrats, you have discovered why in TDD you write the test, watch the test fail, then make the test pass, then refactor. AKA: Red, Green, Refactor

[–] madcaesar@lemmy.world 1 points 2 years ago (1 children)

I'm really having a hard time visualizing this. Do you have an example?

[–] fiveoar@lemmy.dbzer0.com 1 points 2 years ago* (last edited 2 years ago)

Sure, so say so you have a requirement to add two numbers

You write a test that has two two inputs and the output Run the test and watch it fail, check that the output is what you expect so you know the test is working

At this point you have no implementation and you use this opportunity to confirm that the test will work, by checking it is failing how you expect. If you are pairing sometime I teach that you should call out what you expect, kinda like in American pool. Sometimes the test passed in this case, this is your opportunity to break the test and confirm it will fail (though this is often a sign you did too much work previously, and might need to check if you really are making the smallest possible change)

Do the minimum to correct the problem described by the failing test (you can follow the transformation priority premises here if you are familiar with it)

At this point you have only implemented the simplest possible code, this makes it really easy to spot if there is a problem with it because of some flaw in the test, and you have confirmed the it matches your test

What's more you can confirm all, and only behaviours described in the test are implemented

Look at the code and decide if you can simplify it, do any refactoring

Got to clean the kitchen because if we don't clean the kitchen we will have to clean the garage and we don't want that because it's a bigger job.

repeat

Why this works is that the code is developed in a TDD style forces you to move in smaller steps meaning bugs are shallower when they do occur. You aren't dealing with a 20 complex lines, you are dealing with a return const, or selection, or etc. The scope for the test being wrong is reduced and the amount of implementation is reduced, generally the tests end up more concise and smaller too and the interfaces are user friendly too because you didn't think how do I calculate this, you thought what would be a nice way to call this.

What's more it encourages an example driven approach that leads to developers thinking about the most sensible input data over and over again, and what that should output reducing the chance any one wrongly implemented test wouldn't be picked up by other examples.

TL;DR, the driven word is the key, a test that is illogical will never drive you to the working code

[–] SrTobi@feddit.de 4 points 2 years ago

And then in the end we realize the most important thing was the tests we wrote along the way.

[–] iAvicenna@lemmy.world 3 points 2 years ago

Run the test a second time, test passes. silently move to the next step.

[–] redcalcium@lemmy.institute 2 points 2 years ago

This is why you write the tests first before the actual code.

[–] sebsch@discuss.tchncs.de 1 points 2 years ago (1 children)

Meaning your tests where to complex.

[–] Speculater@lemmy.world 1 points 2 years ago

I always name my tests too complex 🥲.

[–] Alph4d0g@discuss.tchncs.de 1 points 2 years ago (1 children)

I've seen some interesting thoughts on TDD with fail, pass, refactor assumptions. I'm curious if anyone here is writing functional code in order to then make a failing functional test pass i.e. BDD / ATDD. This follows similar logic without the refactor assumption. I've seen strong opinions on every side as far as this is concerned. On a team with Dev and QA competencies, I've heard a number of devs glad to get QA out of the bottleneck and put their knowledge to better use.

[–] organicmolecules@lemmy.ml 5 points 2 years ago

Depends. If I'm working in an existing system and I know what the shape of the thing I'm writing is, then I might write the test first and tdd it out as that process is usually a bit faster for me.

If I'm developing a new feature I'd probably spike out a solution and write an acceptance test to match it, then if I'm feeling pedantic I might throw away the spike code and tdd it back up from scratch but I haven't done that in a while now.

This all depends on the language and the abstraction layer I'm at.

load more comments
view more: next ›