6 ms·
The abstraction is consistent though, and familiarity is a good thing when navigating a codebase which has N amount of other devs pushing to it every day. I pr
by hacker_9 9y ago
The abstraction is consistent though, and familiarity is a good thing when navigating a codebase which has N amount of other devs pushing to it every day.
I practise TDD for peace of mind - if I add new functionality to existing code I can be 99.9% sure I haven't made any regressions. When a client's system goes down on a friday, I can 99.9% guarantee it wasn't my code that is at fault. If I have to work at the weekend to update a production server, I'm 99.9% sure it'll go smoothly as my tests say it will.
- FanaHOVA 9y agoIn this case, what's the difference if you write the test before or after though? You would still be covered. I don't lean in either directions in this argument, just curious to understand.
- hacker_9 9y agoThe difference is night and day - writing tests first means you write 'testable code' from the beginning. Following the red, green, refactor mantra means that for every change to your code, you already have a failed test waiting to pass. The result is your test cases make a lot more sense and are of a superior quality. To liken it to something you may be familiar with - when commenting your code, do you think it's better to add comments in as you write the code? Or add in the comments at a later date after the code is all written? I'm sure you immediately know which approach results in better quality commenting, and it's the same with TDD.
- seanwilson 9y ago> To liken it to something you may be familiar with - when commenting your code, do you think it's better to add comments in as you write the code? Or add in the comments at a later date after the code is all written? I'm sure you immediately know which approach results in better quality commenting, and it's the same with TDD. Not to take the analogy too far, but usually when writing a chunk of code I can keep it's behaviour in my head for a good amount of time and find it's best to add comments at the "let's clean this up for production" phase when you can take a step back and see what needs commented. If you comment as you go, you'll have to update your comments as the code changes and sometimes throw comments out which is a waste of time. Likewise with tests, I'm not saying write them far into the future, but I think having to strictly stick to red/green/refactor is going to waste time. What's wrong with writing a small chunk of code then several tests when you're mostly happy with it? Or writing several tests at once then the code?
- hacker_9 9y agoPeople just don't write comments or tests after, that's the problem. If you do then that's fine, but after trying both routes I actually find TDD to feel like less work - not having to wait on large build times and manually navigating the UI actually makes for a more fun experience. Instant feedback being the fun part. Additionally writing tests 'after' always feels like work to me and I end up hating it, especially when I didn't write it in a testable way to begin with.
- seanwilson 9y ago> People just don't write comments or tests after, that's the problem. Doesn't that get caught in code review anyway though? I find being forced to write tests first can be clunky and inefficient. Also, I've worked with people who insist on the "write the minimum thing that makes the test pass" mantra which I find really unnatural like you're programming with blinkers on. TDD takes the fun out of coding for me sometimes. Generally I'd rather sketch out a chunk of the code to understand the problem space better, figure out the best abstractions, clean it up then write tests that target the parts that are most likely to have bugs or bugs that would have the biggest impact. I find when you're writing tests first, you're being forced to write code without understanding the problem space yet and you don't have enough code yet to see the better abstractions. When you want to refactor, you've now got to refactor your tests as well which creates extra work which discourages you from refactoring. When the behaviour of the current chunk of code you're working on can still be kept in your head, I find the tests aren't helping all that much anyway so writing tests first can get in the way.
- hacker_9 9y agoWhat you describe is the typical mindset against TDD, it's difficult to explain the benefits, and really you just have to experience them for yourself. Changing your mindset is difficult, I know, why change what works right? My only tip is to keep an open mind about it, as TDD benefits are often not apparent to begin with, they only come after a couple of days work or weeks or months later or even years later. You find that you need to do less mental work, as your tests make the required abstractions apparent for you. 'the minimum thing that makes the test pass' ends up being the complete solution, with full test coverage. Any refactoring done is safe from regressions, because of your comprehensive test suite. And when other colleagues inevitably break your code, you already have a test lying in wait to catch them in the act.
- konart 9y ago>do you think it's better to add comments in as you write the code? Or add in the comments at a later date after the code is all written? Define "all written". If we are talking about a new function - obviously you write you comment for it after the function ready to be commented on. And obviously you won't be commenting every string you put there, right? Now, if we are talking about the whole new feature, that can consist of many functions and whatever - yeah, you usually comment your code in the process of writting the feature, rather than doing it at a later time, which will never come.
- ryanmarsh 9y agoComments / tests are a bad analogy. HN will over index on this and go down a rabbit hole.
- markatkinson 9y agoI also find when following red, green, refactor that you end up producing more targeted unit tests that are more expressive of the code you are testing. Trying to write unit tests afterwards lands me with something that appears as more of an afterthought or add on. It doesn't have to be this way I suppose, but it is more prone to. This might be because I am more used to the red, green, refactor method though.
- cjsuk 9y agoIf you write the tests afterwards, you find where all the tight coupling and crap abstractions you accidentally did are afterwards. That leads to you either not writing tests or having to refactor bits of it. It's easier to do this much earlier on.
- cjsuk 9y agoExactly this. Confidence is everything. I can actually write entire features with appropriate test coverage from the ground up and they work first time and have close to zero defects in production. It's amazing when you spend 5-6 days writing code that does nothing and at the last moment, everything slots together with a few integration tests and wham, feature done. Not talking trivial stuff here either; big integrations across several different providers/abstractions, bits of UI, the lot. You see a lot of people arguing against this but I'm going to be honest, they churn out a lot of stuff that doesn't actually work.
- leftsidedhorn 9y agoHow do you deal with http interactions in test? Do you mock it or maybe save it to disk to replay later?
- cjsuk 9y agoThat's an integration test really. The clients all have an abstraction around the http endpoints so nothing touches integration in unit tests. The advantage of this is you deal with transfer objects only in the code, no HTTP which would violate separation of concerns. I use HttpMock myself in test cases which fires up an http server for personal projects. We use Wiremock commercially.
- mohaine 9y agoHere is how I handle it 1) Write a test that runs the service and saves output to a file. 2) Mock out the call to just return the data from the file and validate results. 3) If you need variations on this data just modify the file/data (often as part of the test) I usually leave number 1 in the code but disabled since it often relies on remote data that may not be stable. Having the test run more than once is not very beneficial but being able to run it later and see what exactly has changed is great.
- gurkendoktor 9y ago> You see a lot of people arguing against this but I'm going to be honest, they churn out a lot of stuff that doesn't actually work. My anecdata cancels out your anecdata. The TDD practitioners that I've met have, without exception, written code that worked fine for only the one case that they've tested. Example: They'd test a method for sending a message with the string "hello". Turns out the method didn't URL-encode the message before POST-ing it, and sending anything with a space was broken. They were confident and pushed the change. Not saying you're wrong, just that TDD doesn't seem to work for everybody, and can even be a distraction.
- pjmlp 9y agoIs GUI code that 0.1%? Because I am always keen to understand how to TDD GUI code and I don't mean the data model behind the pixels.
- hacker_9 9y agoVisual tests are more general, and are more akin to putting up barriers on either side of a bowling lane so the bowling ball stays within it's lane (with room to move about still). For example when using Angular, you write 'Page Objects' that have methods such as .getTitle(), .clickListItem(3) and so on, and can then write assertions to make sure the UI changes as expected by inspecting properties [1]. I usually find I build a general page object first ('this text is somewhere on the page'), then write the UI, then make the test more specific if I can after (but it's an art, as too specific and you risk creating too many false negatives when you make UI changes). (Also as you are interacting with the UI, these would be known as integration tests.) [1] https://semaphoreci.com/community/tutorials/using-page-objects-with-protractor-and-cucumber-in-angular-applications https://semaphoreci.com/community/tutorials/using-page-objec...
- cjsuk 9y agoWe use Ranorex for this: https://www.ranorex.com/ https://www.ranorex.com/
- pjmlp 9y agoInteresting, thanks for the link.
- TeMPOraL 9y agoI think so. I don't know how to unit test GUIs either.
- oddlyaromatic 9y agoI saw an enjoyable talk recently about snapshot testing. I don't know too much about testing generally but it seems like it could be relevant: https://facebook.github.io/jest/docs/en/snapshot-testing.html https://facebook.github.io/jest/docs/en/snapshot-testing.htm... is the general idea but it doesn't have to be confined to jest/react Edit: Slides from the talk I saw: http://slides.com/bahmutov/snapshot-testing http://slides.com/bahmutov/snapshot-testing
- coconut_crab 9y agoI also practice TDD, but with a different 'T' - Type Driven Design. I find them much easier to reason about with types and safer (you can't compile your code if it doesn't pass the type check). Just model your data as ADT and pattern matching accordingly. Of course, types alone can't represent every error cases out there (especially the one related to number or string), so I still write Unit Test for those cases. But the number of Unit Tests needed is much lower.
- marcosdumay 9y agoThat would be ATDD - Abstract Types Driven Design. It completely fails on concrete types. That's the reason haskellers create a DSL for everything.