1. Yes, break down your code so it's easier to test each part, but don't over do it. Not everything needs to be it's own tiny module. 2. Yes, writing tests is good, but don't just test for one thing (like in your examples), try to test for every scenario. For example I saw you tested for someone bellow the minimum age, but you should also test that someone at the minimum age is allowed. 3. It is a good idea to check for regressions. Also, I have seen some people that implement specific tests after discovering bugs so that it stays fixed. It is also important to mention that there is no such thing as writing bug free code, as there will always be some kind of bug, but it's up to you to make it easy for yourself to lower the possibility for bugs to appear.
When I and others advocate against unit tests, it is not because we advocate to running no tests, but rather that you usually want to build up your test sweep with different things than unit tests. Unit tests are kind of like a small hand shovel. It is a basic tool that you can easily get most people to use, and while you can in principle dig out the foundation of a building with such a tool, there are usually other better tools to do at least the majority of the job. Aside from just taking a ton of work if you use it for testing everything, they also tend to have a lot of other problems when the scale of the system becomes a bit larger, which generally has the effect that you are unable to detect a ton of bugs. The first main failing point is that composition of bug-free components does not lead to a bug-free system. It is easy to see this by realising that each of the operations you write in your program is expected to be (mostly) bug-free in terms of the programing language, but their composition into a program is expeceted to easily yeild a ton of bugs that are not related to bugs in the components, but rather in how they are combined or assumptions on how each component works. The second main failing is that it is hard to write unit tests for bugs you did not already anticipate and therefore already considered when you wrote the code. Combine this with that the scale of the units in unit tests are usually so small that you could keep those things in mind, and you will that in a lot of cases you can mostly only test for things you already took an effort to not have as bugs. This means that unless you are uncertain about a unit working, it will mostly not be able to find any significant bugs (mostly it will find typos/grammar problems). Combined, it means that unit tests are really poor at covering the main areas where you can expect to find significant bugs: at complexity and for things you did not consider. Another strike against unit tests, is that they are barely ever actually failing after they were written in the first place, and as such does not give that much value in regression testing. The problem here is that tests mainly fail where there are breaking changes in the code covered directly underneath them, but unit tests usually cover such small areas that you rarely need to make significant changes underneath their covered areas, and most changes you make on that level are often written outside those units in some way, such as written in a new function instead, for which the old test does nothing and you will have to make new tests to cover that new thing, and that does not give the same kind of safety as having something covered under already working tests. There is also the issue of actual coverage of new tests introduced, which means that when someone submits something new, then you would rather know that it was covered by existing tests rather than trust that whatever tests they added are enough to cover all the potential problems with the new thing they introduced. Here I am not talking about line coverage, but coverage of actual possibilities for bugs. This is never going to be 100% with any method, all you can do is try to get the coverage as high as reasonable for the amount of resources you are willing to throw at it, and unit tests and setting up coverage for each unit takes a ton of resources and has a ton of diminishing returns in terms of pushing it higher, because it has a really hard time actually covering a lot of potential bugs. All of this might make me sound like someone who are fine with leaving tons of bugs in their code, but that is not the case and this is the kind of mentality I used when I set up the ways to keep bug-critical software safe, the kind where bugs are expected to be associated with tens or hundreds of millions of euro/dollars in losses. I just do not trust unit tests to work well enough for that case, and especially not if I had to do the job with a similar amount of effort, as the amount of work to make that many unit tests would have likely costs similarly huge losses due to delays in deployment of the system. Generally speaking, tons of unit tests are a bit similar to tons of comments, in that they are mostly a sign of an intermediate level, as beginners learn to add comments to explain their things and add (unit) tests to generate trust in the system, but experts instead look to remove most of either by using better and more appropriate tools. For comments it is often about making comments redundant, by simply having the code be self-explainatory, and for tests it is largely about writing fewer more powerful tests. Generally speaking, large scale tests, such as more like intergration and functional tests, tend to form a good basis for your regression test sweep, and for more local areas of complexity things like property based testing can be used to look for unrecognised problems. I personally also like to sometimes do some manual testing of the principles in something before I write the actual code, as this both gives better insight and because it catches the potential bugs earlier also reduces the cost of finding and handling those bugs - also it is less borring, and that is important both for my enjoyment and to keep concentration and work quality high.
Couldn’t agree with all your points more. I have a problem with unit tests not because I don’t want to write them but because they do do a poor job of testing any complex portions. I find good integration tests, functional tests, and end to end tests to be worth their weight in gold
@@psychic8872 He basically means, unit tests only tests direct code, no complex code.and adds more noise to the code than it solves and give false sense of bug free. It also hides bugs that unit tests does not cover because you are unaware that it missed something. I also experienced cases where the unit tests was testing mocking and not the real code. No one knew, because everything was green. When you are a beginner developer, unit tests will save you, but when you have decades of experience, unit tests are additional noise preventing you to see the real code. Code can be self tested in the way you construct your code. The code becomes the test itself and you did not waste any time and energy creating unit tests. Instead of 10 lines of unit test code for 1 functional line, you get 10 lines functional code for 1 line of unit test code. Doing this way you can modify code way faster, without dragging 10.000 uni tests with you that prevents any change in your code.
One example, I just found an error in C# code that unit tests failed to catch. double valueAsDouble = 3.1 int valueAsInt = (int) (valueAsDouble * 100) valueAsInt became 3100 in the unit test but in the code somewhere else 3109. Same project, same compiler, same codebase different outcome but in extreme rare case..
Maybe the only way to write code with no bugs is writing no code at all. Writing tests help to mitigate what we know that could go wrong, but we can't be 100% sure that our code runs perfectly 100% of the time, because we can't know in advance all the contexts of use of each piece of software that we build and we use.
It’s simple. If you aim for 100 percent bug free code… you might land somewhere in the 90 percent range. If you just say, what’s the use! The code will always have bugs! Then people stop trying and then the rest should be obvious.
@@kantancoding Yeah, that's the point. We should aim for the 100% knowing that we did a great job, and tried to prevent all the errors we know that exists or we foresee. The thing is: if we approach the code with the idea that we should write 100% bug-free code, then maybe we're missing the point of writing tests, hence writing no code at all. Tests help to document what we know, not the future.
The thing you're doing in your example, which is also critical, is moving towards referential transparency. Lots of little functions that behave functionally--give them parameters and they return the same value. I don't endorse it universally, but where it adds clarity and testability, referential transparency is always a good thing to move towards. That also produces code you can more easily eye-test: the less state, the less you're trying to keep track of in your head, the more obvious the bugs.
I used to hate writing unit test. Then I joined a team that has no unit tests and a massive monolith where causing a regression bug is not too hard. It's the regression testing for me that has the most value as time goes on.
These three principles 1. aren’t laws 2. aren’t going to stop all bugs: at best tests are heuristics. Look up Dijkstra quote on testing We should use behavior/micro-workflow texts. Where we don’t test the internals. You are showing how to tests internals Bad code making it into master/trunk should be caught before going out. Breaking master is fine. Allow self-approvable PR’s and use pair programming for continuous review Keep working at it. You’ll get there and fix the whole in this video. Great to put something out there
I've catched the Trim issue because I made some stuff in the past that I needed to cut spaces from both sides, and thankfully the Go developers already thought about that
I cannot stress how useful having a test to document code is. I have 10 years of experience as a developer. I can't count the number of times I've been confused as to why a piece of code seems to be going out of its way to do things a certain way but there are no comments or external documentation to explain why and the person in the git blame hasn't worked for the company in 5 years. This goes one of two ways: 1. I find a unit test that explicitly tests that part of the code and all is clear. 2. I start ripping things out and fooling around with it to see how it breaks. The ✨I ✨add the unit test. The second takes *a lot* longer
As a non-programmer starting writing some code, this cleared up a lot more than alle the other learning tutorials did. Most talk about the basics, but not on how to write code and hos to use functions. This was very clear and also clear WHY. Thanks!
@@munchduster2815 For me a bug is an error in the code and can be found by analytics. But there are other reasons why your code does not work as intended: - the customer communicated a different problem than he actually had - the problem changed over time - the problem was not specified correctly - the customer does not stand the reality check. Those are all reported as bugs, but may not be solvable in code without altering other aspects of the project like the specification or definition of the problem you are trying to solve.
@@MrHaggyy if the customer communicat d a different problem than they had I agree that isn't related to bugs, but that the program is working as *you the developer intended*. Similar reasoning for the other examples. Those are problems about developing the wrong product because of poor communication. Just because a user reports something as a bug doesn't mean it's a bug. An extreme example could be that I think Minecraft is too blocky and report that as a bug, that doesn't mean that Minecraft being blocky is a bug, it's completely intentional. Similarly if a was asking a developer to make a voxel game and the outcome was like Minecraft (blocky) and I was expecting not blocky like Astroneer. (Taking a second to say that although I debate your definition of a bug, I acknowledge that you are identifying issues that happen in real projects around customer requirements and interaction which affect the project beyond just the code written)
You missed the real first law. Write a unit test BEFORE YOU TOUCH the code as a baseline. Even modularizing code can miss subtle requirements that aren’t called out in the code. So write a unit test against the old code FIRST.
Not quite, but the key is that you want to ensure that there are tests to ensure that the functionality and features expected of old code already has tests before you go and make changes to it. Generally though, you want to not be writting new unit tests for this purpose, because tests covering this should have been established long ago and you likely do not understand/remember all the parts that needs to be tested for when you are working on others/old code. if what is already there is insufficient, you can add in some tests, but unless you already have a good understanding of that piece of code you have to come to terms with it being hard for those tests to properly cover all the things that should be covered with tests.
The real value of tests, both unit and regression, isn't in finding bugs when they're written. As written they had better pass. Their nominal value is in maintenance, ensuring you haven't screwed something up. Even more valuable than that though - they give you confidence. A good suite of unit tests (for isolated tricky parts) and regression tests (for overall system behaviors) gives you the confidence to clean up your code. Any reasonably complex system is always going to have things you wish you had done better, or knowing what you know now things you'd have done differently. There's a reluctance to do that refactoring and cleanup of tech debt because no-one wants to break a running system. A good suite of tests gives you the confidence to make those clean up / refactor efforts knowing that you're unlikely to quietly break something someplace else. The net effect is your code steadily improves due to those incremental refactors.
Unit tests catch the easiest kinds of bugs at a cost of a massive test suite that needs to be written and maintained. Unless you're nasa and are going to do every other kind of test under the sun as well you're probably one of those companies that has more lines of test code than production code and yet still ships buggy software. Applying cost benefit analysis and developing in a manner that catches the kinds of bugs that are actually problematic is much more efficient in terms of developer resources. It's a bit of a bold assertion to say that in all circumstances you should write unit tests. Especially with examples like this. Few people suggest you shouldn't test your code. No one worth listening to does. But people very often have good points and strong arguments for not writing unit tests, especially not by default for every piece of code. Your argument is arrogant and misguided.
Have to respectfully disagree. I don’t work at nasa, I work in fintech and these so called “easy kinds of bugs” (not even sure how you classify a bug as easy. A bug is a bug and can have user impact) scaled to our 100 million + users would be detrimental to our business if core flows are impacted.
@@kantancoding Fintech is another reasonable area to do unit tests, sure enough. But an easy bug is one that is trivial to observe, identify and debug. It's the kind of bug that will be observed and fixed with minimal effort long before shipping without any extra effort. Not all kinds of bugs are equal. Obviously depends on how you ship software and what kind of software you're making. Some bugs are not easy to observe, identify or debug and those tend to be the kind of bugs you really want to invest the time to deal with and those tend to be the kinds of bugs that unit tests won't catch. It's usually at the intersection of units of code and in larger systems that trickier semantic bugs crop up. If you spend all your time wriitng and maintaining suites of unit tests that test things that really aren't complicated you're wasting time that could have been spent finding the important bugs. And yes some bugs are more important than others. I'm genuinely surprised you wouldn't recognise that not all bugs are equal. Sure I expected you to disagree but it's surprising you would attribute equal weight to all bugs and not recognise that some are trivial to fix and some are extremely difficult to even identify let alone reproduce. What would you say to people who essentially write unit tests, make sure the code works, then bin them rather than maintain them? I'm sure you'll say thats foolish and regressions and all that. But if you've written some maths code, and now that maths code is working, and you're not going to touch it again, why would it make sense to run tests for that maths code every single time you're building your software? You're slowing the code-debug-execute cycle drastically, adding code to maintain (which itself can have bugs) and for very little benefit (if at all) yet that is what you're arguing for with an authoritarian manner and calling people who have recognised that testing software is more nuanced and that other kinds of testing might be more economical and effective fools. Not all bugs are equal. Unit testing isn't the only way to test software. What are you, the sith. Do you think you're the sith or something?
I see most comments are already controversal: As a non-professional, hobbyist coder, I have to say most bugs come from complex interaction of different modules, random (invalid input) that you did not foresee (hence could not be put in a unit test) timing issues and race conditions etc. Such unit tests only catch the simplest typos which you would catch already if you just made a few simple tests of your newly written/modified function.
I think that it's important to distinguish between different platforms. On mobile for example, having unit tests for non logical functions, is just useless and makes the process longer for no reason. We should learn to adjust our thinking to the platform and scenario which we are coding in
I'm a front-end developer, I really hate unit testing a component. My other collage is unit testing a component to make sure it renders on browser, to make sure the text is show on dom, why? It really pointless. I rather using E2E for testing the web application (business flow) and ONLY unit-test a PURE FUNCTION (without dom or other shit like that).
I'm consulting right now in a company whose culture doesn't understand any of this. This video is correct. If you find yourself in a place that only does integration tests and thinks 70-80% code coverage is fine. You're in amateur hour. And it's gotten more common in the past few years. Don't worry, they're wrong, and you who will test all the things and write small code are right.
Totally agree. Integration tests are cumbersome and very slow especially if your unit to integration test ratio favors integration tests on large projects. Many integration tests can actually be refactored to unit tests in my experience.
Type checking only really handles one specific category of bugs. The idea that type checking would magically make bugs go away is more of a fever dream. I have written programs in enough different languages with different level ot type checking to know that you still have plenty of potential things that can go wrong even when type is correct. Heck, a lot of those other types of bugs tend to pop up more in languages with very strict types. I see a lot more "off by 1" and problematic recursion conditions in languages like C/C++ and Haskel compared to languages like Python. Of cause if you are living in one of those type nightmares like javascript then the conditions change, but often you have that the flexability of less strict types means you do not have to do so much manual low level manipulation where those other types of bugs tend to pop up.
It took me under a minute to spot the suffix thing, without even knowing the language this code is written in (suppose it is Go?). Wrote ton of code in my life without writing a single unit test and I'm still convinced it is wasted time if you are a good developer. It can be useful in some corner cases where you have functions that implements particular algorithms, but nothing more than this. That said, if I need to write them, I can write them. Just, I don't need them.
Well if the dev doesnt find a bug without a test, the CI/CD Pipeline does its job and the reviewer doesnt find it, there is potentially a chance that the customer also won't find it in production.. 😂
Law 0: Rules don't matter when met with reality. The reality is your customer doesn't care about how clean your code it as long as they get to do tasks with as little disturbance as possible. If I have to go through 20 pop-ups to start using your website. Forget about your "clean code".
This is not enough to make it bug free, but it is sure a good advice. While there is no proven way (yet) to guarantee nonexistence of bugs, there are few practices that can make the code almost bug free. Coincidentally, each of these practices include this testing advice as a requirement, but that's just a one tiny part.
I have some noobish questions Should you test for parameter types? I.e. ensure that a function only accepts a certain parameter type? Do you have to consider all "edge cases"? For example, in the isValidAge function, the critical points are at, below, and above minimum age. But what about 0, 1 or negative age? What about large ages, like 60? 100? 99999999? Is this related to the "business logic" jargon? I admit I don't write tests at all. I know their value, but I don't know when is a test "good enough". The questions above, I swear I've tried searching about but I couldn't find a very good reference.
1:08 , Extracting those things into isolated functions is great for readability and makes reasoning about the code much easier. However, I often come across functions that are untestable because they are private and not available for testing. There might be one public function that calls these five private functions. In such a case, what should you do?
You should always test through the public functions. If you need to test private functions then this is a smell that indicates you should split it up into separate modules instead (e.g. classes if you're using a language with classes)
Even if all imaginable checks are performed, there is no theory, nor metric, nor tool, and particularly no "laws", that can tell us how many important bugs remain. We must test - experiment in an exploratory way - in order to have a chance of finding them. No one can know in advance where the unanticipated bugs will be and therefore what scripts to write. Not denying the value and importance of unit tests, but there are not a silver bullet against bugs in the code as you suggest by the title of your video.
Unit tests help void somethibg liek segfaults. However in my experience (embedded) there are far more functional bugs that sometimes only get noticed in field tests.
Hey, very nice video, the importance of good tests (unit/integration/feature) is paramount. By the way which font are you using in the video? it looks very nice!
Ok do a regression test often. And... once a test failed what then? Should I move the constante back into the method for example? Or change the unit test?
You should look at the code and the test to determine which one to change, but it would normally be a regression in the code. You don't just change unit tests to match what the code does, you test for desired behaviour. The only time the test would ever change is if there's a bug in the test code or if the desired behaviour has changed, but usually a test starting to fail after a code change means there's a problem with the code that was changed.
I don't understand why you test an abvious thing. Also, do you test your tests? func test_programing_language_is_working_fine(t *testing.T){ assert.True(t,1+1==2, "expected 1+1 to be 2") }
@@kantancoding it does take more time and probably has discouraged me from fuller coverage but it feels like better quality test and it was the way I learned so it seems more natural I guess you’d say. But I have found myself trying to make it a creative exercise to make it less painful. Maybe it’s log rocket but some org has a great blog on it. I’m doing it on a personal project so it’s not as deadline critical which offers some grace for this approach but I like it (far as liking testing can go haha) Keep doing your thing man I really enjoy your channel and attitude towards learning
Fully agree with all 3. But holy shit I'm so envious of people that have tests that execute in 2 seconds. Usual test run at my company is 15 minutes and it sucks when you have some trivial error or even worse if compilation fails after 5+ minutes due to some typo.
That must include integration tests right? Integration tests for the larger services I work on take similar times which is why I advocate for writing unit tests instead of integration tests where possible. Can run thousands of unit tests in less than a minute.
@@kantancoding Lets say that it could be called like that. Code base is gigantic and modules are highly dependent on each other and on top of that everything is tied to hardware on which most tests must be run. So in most cases you need to spin up the whole system to run any tests.
You need to write unit tests and not just integration tests. With a unit test you only test that piece of the system in isolation. Anything external that it touches, such as the database or file system you replace with a mocked version. Trouble is that a lot of legacy code wasn't written in a way that allows you to easily do that. The best way of getting quick testable code is to write the test first and then write the code to make the test pass. That way your code is structured in a way to make it easily testable. Once you start doing that and making your tests small then are well on the way to do Test Driven Design (TDD). This is a mindshift and feels weird at first, but it works. I'm a senior dev with nearly 40 years experience - I found it weird, but I'm now reaping the benefits,
Start moving your legacy code behind interfaces to modularize it. Then you can stub those legacy interfaces and avoid having to spin up real objects when unit testing other units. Even in integration testing, you should never have real versions of code whose functionality is irrelevant to what you are testing. If you do, then you need to make that other functionality independent of the system under test (modularization).
The trick to handling this is to have different options for testing. You typically want at least one way to run tests locally that take less than 10 seconds, and maybe one that can be completed within a few mins. The first of these is used like a mental handwashing that keeps you reasonably sure that the code still mostly works, and enables you to quickly know when you start encountering bugs in your new code. The next is used to be fairly sure that things are fine before you push changes to a place that matter a bit more, such as just before you start writing your pull request/getting ready for a merge. Aside from these you might have a large test that are more throrough for more important steps, such as before pushing something to release, other important places or when merging big changes.
unit tests for functions that can be easily verified by inspection is in fact not a good thing. You don't need to write unit tests for things like "shouldReturnTrueWhenAgeBelowMinimum". Granted its just an example but people watching this will take that at face value and write tests for trivial functions that do not need unit tests. There is no clear guide for what is considered a unit. You risk creating units that are too granular. edit: also, factoring out code that is both small and never reused is stupid too. Don't pull something out into its own function if its a handful of lines and is never used anywhere else. You're just adding to the call stack for no good reason. Write readable and commented code instead of pulling something out into its own function. If it's a massive chunk of logic or is duplicated, yes factor it out.
And taking that logic further, the only real "unit" that isn't granular is the entire application, and the only test case that encompasses all use cases is production. I.e. test in production. Seriously though, if you can't write code without bugs then you can't write tests without bugs. Things will break eventually, might as well optimise to allow you to fix it as fast as possible.
@@MarthinusBosman There are countless levels between test in prod and test every minute bit of logic. You should be pragmatic in what you define as a unit. I agree. And what helps most with fixing as fast as possible is being able to trace through code as easily as possible. Which you make hard by over-modularising your code.
Generally speaking, pulling out a non-repeated function is a readability vs performance choice. Most of the time the trade-off is such that you want the readability over the performance. Generally speaking the purpose is to make it easier to see at a glance what a piece of code does, and how that interacts with surronding logic. This requires one to get to a certain level in the art of naming before it gives much value though, and if you are bad enough at that art it is going to be a net negative in terms of readabilty. In terms of factoring out really small functions, then I have actually found bugs in other peoples code when I used that to make sense of larger mathematical expressions. Most of the time single operation functions feels kind of weird. Boolean checking is weirdly one of those cases where it often makes sense to do rather banal functions, because the mental gymnastics of translation the mechanics of a boolean check into its purpose in relation to the surronding logic means that grasping the logic of the control flow takes quite a bit more effort.
I as somone who cant do Test, do Tests If possible, im working in a language / envoirement that doesnt Support Tests so 1 Change = deploy to Test system and Test in the normal User UI If the Change worked or step trough Code with Debugger Luckely our Codebase isnt that large only ~20k lines Source Code +100k lines Translation and Design files
I think there's quite a few problems in this one. The first example is not a good example of modularisation 😅 simply splitting things into functions does not make code modular. Many would say the code is worse now because it is split up unnecessarily - now there are multiple functions to read instead of just one. Modularisation means decoupling code, which in this example is not what's happening - the implementation jumps across functions, but it is still tightly coupled. And code that is tightly coupled but spread out is actually one of the worst things for maintenance and readability. Secondly, we should only write unit tests against public interfaces. Writing them against these private implementation details is the road to pain and suffering with brittle tests that need to be rewritten every time something changes. What is shown is not good unit testing practice, and in fact is how many people end up with the false conclusion that unit testing is pointless and painful, because they end up essentially just having to write all their code twice. I like that we're teaching people about the value of unit testing, and we've got the right idea here with how to avoid regressions, but this is not a great example of how to do it, unfortunately.
Modularization doesn't always have to mean decoupling with an interface and abstracting implementation details. Like showed in my example, you can test code segments in isolation simply by breaking apart large functions into smaller functions and using DI(Dependency Injection). This is another form of modularization. The common argument that having "multiple functions to read instead of just one" makes things difficult to understand is not a good argument imo. Like with all things, there's a tradeoff. Needing to jump to function definitions vs needing to resort to writing integration tests to test core logic that doesn't have network dependencies etc. "Secondly, we should only write unit tests against public interfaces. Writing them against these private implementation details is the road to pain and suffering with brittle tests that need to be rewritten every time something changes." In response to the above point. Us engineers tend to state our opinions as hard rules. I'm guilty of it too but in actuality this is just your opinion. You say that we should only write unit tests against public interfaces. Public to who? And what examples did I give where the tests test private implementation details? For example, we aren't testing that the TrimSpace method is doing what it is supposed to do. Those are implementation details that are a black box. We are testing that we are using the correct method in our own function. Admittedly, the examples are oversimplified just so that I can explain the points more clearly and so that people can easily follow along. But for more experienced people, you should be able to replace the oversimplified examples in your mind with more real world examples based on your experience. Anyways, I've enjoyed your comments on both of my recent videos. They seem well thought out so thank you for taking the time!
@@kantancoding hey I appreciate the response! And I hope I'm coming across as helpful not just negative! I've extensive experience teaching junior engineers, and like you say the senior engineer understands what you're saying and can contextualise it. The junior engineers cannot, and so what I mean to say is the examples given can lead people astray. Dependency Injection would absolutely make that code modular in the way it was split - I might be wrong but I don't think DI was mentioned in the video, and this is a key detail here that is often not obvious to juniors. A similar detail that can cause a misconception is avoiding hard coding the company by extracting to a constant, but the constant is still hard coded - it's just not inside the function any more. Similar to just moving code into another function does not produce modularity, moving a literal to a constant does not remove hard coding. Again, a senior gets that but a junior might not. Unit testing against a public interface is more than my opinion, it's more or less the only way that unit testing is generally useful 😅 you can test implementation details if you like but you'll just end up writing your code twice every time, which is where many people go wrong with TDD and end up jaded on it. You want to treat your code as a black box, and only this will produce the very real and very powerful positive outcomes you mention in your video. Public in this sense means where the "seams" in your code are, in other words the public edges of your abstractions. Usually in C# or Java worlds this is an interface, in JavaScript it would be an exported function. If you are exporting a function, or promoting a class member above private just so that your unit tests can see it, this is often an indication that you're testing implementation details. When you decide what a piece of code does, you encode its contract with the world in the tests you write against it. The tests (like you very rightly pointed out!) then form machine verifiable documentation to others about how to use the code and what it does and does not do. So in that sense what we mean by public here is what does a caller need to know and care about, and what shouldn't they know and care about? And this is the key art of software design, i.e. choosing useful, meaningful abstractions that effectively modularise your code. I enjoy your format, and I think you're sharing really good ideas! I do think these kinds of details are important if you are aiming to teach your ideas accurately (based on my own learned experience teaching poorly on many occasions!). I hope it helps!
I see! You make some good points. It’s actually very difficult to fit many details into a short video that people won’t immediately click off of out of boredom so I’m still trying to find the balance of what should be implicit in my explanations and what should be spelled out word for word. Anyways, your feedback is valuable and well thought out and I really appreciate you taking the time 🙂
no worries at all, I'm glad if it helps I appreciate that teaching in general is a very tricky thing, and of course throw the constraints of a YT Creator (which I know nothing about) over the top and I imagine it becomes even more difficult! And on top of that you get annoying know-it-all kids in class (like me) who try to correct you!! I'm very lucky to have had good mentors and teachers, and so I've a huge amount of respect for those engineers, like you, that take on the tough job of guiding others and passing on their skills.
Nice video! I have a problem myself writing tests. I can't find the balance between modularity and unit tests. I find myself testing if user click the button the function is called, or if the user fill the email input an email field is sent to the backend. Besides validation logic and empty results, I don't find those tests much useful. How can I write useful tests that are just not checking the default behavior of the programming language?
Yeah this can be a bit difficult with languages that have no type safety. You end up writing a bunch of stupid tests checking if the right type is passed into the function etc. Basically, I’d try to avoid testing implementation details. What you should test is largely dependent on the application you are working on and what business logic is important to said application. Try to test individual responsibilities in unit tests. The important part is correctly defining those responsibilities. The examples in the video are oversimplifications to make the video easier to understand but you should think critically about which parts of your app should be considered their own components based on your particular project.
@@kantancoding thanks for the answer. Yes exactly! I'm looking for content about testing, but every video that I find explain the concept but the examples are oversimplified and I can't find examples of where to draw this line between business logic vs implementation details.
Hey, great video! As a note, i always try to read the code on screen to get more insight, but I noticed that it sometimes doesn't really represent what you are talking about. Like in the end the code shown was the original code, with the 2 bugs. Also I didn't find how the string extraction causes a bug. Is it a go thing?
Yeah that was a mistake! Thanks for catching it. I accidentally did animations/video editing on the old code 🫠 But the code that I ran the regression test for was the updated code!
@kantancoding is technically true, but you shouldn't use the word or term bug free arbitrarily. And also using the word law. Though I get what you mean.
Someone that aims at bug free code never finishes, because to find out if something is bug free takes infinite work. It is similar nonsense as "shoot for the moon and if you miss you will hit the stars", which only works for people that did not take the thing seriously in the first place.
As a self-taught toad that jumps on the fly-laden keyboard, I feel vindicated. I did this habitually because I thought I was _bad_ at coding and other coders would ridicule me. _WHO'S LAUGHING NOW!? HA HA HA HA HA! WHO'S LAUGHING NOW!?!??!?_
In which cases it is worth to write unit tests over integration tests?, in my experience having to use mockups to test things like DB queries usually results in the test not covering really important behaviour, so that kind of test isn't that useful
Since integration tests are resource intensive and slow, I try to write them sparingly. I worked for a company where the previous devs were a bit too trigger happy with integration tests writing them even where unit tests would have sufficed. It became a team goal to reduce integration tests 🤣
Nice video but you slipped in this point: testing cannot verify correctness of a piece of software as it cannot prove the absence of bugs, but it can prove the software is wrong (the bug exists). Thats called falsifiability. But it is still very much important: if you try hard enough to prove the bug exists but you fail that means your software is good enough, which is what you need to achieve most of the times (unless you work for NASA or some very critical applications where you need correctness proof). Correctness proof on the other hand is different from testing in a way that it proves the software is indeed correct (no bugs exist). It can be achieved through formal proofs but are very complex and expensive. In 13 years of experience I’ve never had to verify the correctness of a piece of software and most programmers out there will never see or have to deal with it.
I agree with the overall message you're trying to share. But I can't be the only one who shudders at the sight of those function names being entire novels. What the expected return value is can be communicated using comments or even just by reading the code itself. The way you've written the tests is understandable enough: "age = minAge - 1", "isUnderage" and "assert.True" is clear and easy to understand. You write readable code and you do it very well, which makes me not understand the need for such function names. That aside, I enjoyed the video
The long names for tests are actually pretty standard. It's not so much about the long name as it is about documentation. A well-tested code-base can contain thousands or even tens of thousands of tests and when the business logic becomes a bit more intricate than these examples you can have multiple failed tests for one seemingly simple change. Being able to read through the test names and understand what their testing without opening each one up to read comments or the code itself saves a lot of time and keeps you from getting distracted from your actual goal of fixing your regression. Another reason for verbose test names is that a test tends to be more granular than a method would normally be. You could potentially test 10 outcomes for one, let's say 10 line method. To use one of the tests in the video as an example: 'TestIsBlankStringShouldReturnTrueWhenBlank 'could be shortened to something like 'TestIsBlank'. This would work fine in the video because it's just used as an example, but you would normally test more than just the one outcome. You'd need to test that the method behaves correctly if a null value is passed in or that it does, in fact, return false if the string is not blank and not true as well. Never mind languages that don't have type safety like javascript where you'd have to check if the method handles integers correctly. What would you call the methods for these tests, considering that 'TestIsBlank' is already in use? With that said, most test frameworks have a some sort of description feature that would display the description instead of the test name in the test-runner. The descriptions act as a sort of comment. Sorry for the essay, but there are a lot of intricacies in writing maintainable tests and rather specific reasons for things that look arbitrary or unnecessary. Much like test names, the explanation as to why they are long is also, well, long.
Regression testing isn't an actual unit test, it's more a concept. If you write some code with a unit test attachted to it, and the test passes, the code works. If you go ahead and change a small part of the code you just tested, you can not guarantee that the test will still pass. So you would need to rerun the test. When you rerun the test like that it's a regression test. You're testing if the code "regressed" (no longer works). hope that helps.
A Unit test is about testing a small component in isolation. An Integration test is about testing multiple components that are coupled (or "integrated") together A regression test is about running existing tests to ensure that the new code that you have written hasn't broken existing code. A regession test can be either running all the unit tests, running integration tests or even running an end-to-end test. The test is is about "is this change a step forward or a step backwards (i.e a regression)"
Is it u it test when I test every single part of lua and progres and make it from start ot beginning constantly checking if it does what it's supsoed to do i til it's finished? Like I first make it get the height of the character. Then print the height to see if it's what I expect Then I continue. Or did I do something wrong?
When youtube proposed this video on my startpage I was getting ready to comment what's wrong about it, as I have to do with most coding related videos here. Well, can't do it here. Good work, keep it up. OK, the title is misleading, though. In order to be "bug-free" you must be able to identify and provide fixtures for all possible scenarios and equivallence classes which may even be impossible or impractical in some cases. (This means your content is not wrong, it's just incomplete and a bit misleading. However, you were able to deliver the message in less than 4 minutes and youtube doesn't work without a little click bait here and there, so I'll give you a pass on this one ;-))
Great video, short and concise. But here I'm just doing integration tests these days. I mean, in the code of the example, the database access part is not tested. Doing mocks for testing is just wrong IMO, so you endup writing integration tests anyway. So I might as well test all the branches of a piece of code in one integration test. I used to do both unit and integration tests, but really it's not worth. Doing unit tests you endup using mocks, and it can sum up a lot of code at the end, and more code is always a bad thing. Specially in the case of Go, to test with mocks you have to use interfaces. Adding an interface just for the sake of unit testing makes it all more difficult. Now I don't use interfaces nor mocks, just actual implementations. I use docker to start real components and write a client for my API/service and the tests use this client. I might write a unit test for a specific function, but for the most part I do integration test and never use mocks anymore.
Thanks for the input! I’m of the mindset that integration tests should be created sparingly. They are resource intensive and slow and when you start to get into the thousands of tests on large code bases, it really starts to slow down the development flow to have integration tests where unit tests would have sufficed imo
@@kantancoding I use ory/dockertest in Go to start the containers during tests. It's fast enough. Once the images are pulled, it takes a couple of seconds to run the tests.
Your unit test has a bug in it, same shit happens. Your unit test is always going to only be as good as your understanding of the function. And then you might as well just understand the function instead of moving it along
This is why it must be the developer who made the function who covers it with tests. And if the developer doesn't understand what he's making, he's just not qualified to be a developer. It is very hard to make a mistake in a test that will make it pass when there is a mistake in the code it is testing. It is so hard, it have to be done intentionally to work and it is not too hard to spot unless your code is a huge mess. And if it is a huge mess, that's a reason #0 to reject a PR.
@@ddanielsandberg you realise when the next developer comes, they'll just update the test as well. I think you're missing the point I'm trying to make.
It’s actually rare to need to update tests. Usually only happens when some core functionality needs to change which isn’t common in prod applications since usually you’ll be adding features as opposed to altering the present functionality.
What do you mean we don't spot the bug. I mean, idk much this language, and I see some potential errors in it. How much more to people who know this language.
For any complex system: "Bug free code" in itself cannot be guaranteed. Your title is very misleading. Unit Tests is not all. Your advice is misleading. Tests is the requirements we put on the system. They guarantee that those requirements are always upheld. They do not, however, ensure that your code is bug free, as you could have overlooked or forgot that further requirements also existed. As long as your thinking is not bug free, there can exist no such thing as bug free code in general. This is basis knowledge an any CS course. You should know this already.
Hey Kantan, I believe this video is for your coworker who does not write unit tests lol
😂🤣 no comment brother.. no comment
Thinking about sending this to my coworkers actually 😅
1. Yes, break down your code so it's easier to test each part, but don't over do it. Not everything needs to be it's own tiny module.
2. Yes, writing tests is good, but don't just test for one thing (like in your examples), try to test for every scenario. For example I saw you tested for someone bellow the minimum age, but you should also test that someone at the minimum age is allowed.
3. It is a good idea to check for regressions. Also, I have seen some people that implement specific tests after discovering bugs so that it stays fixed.
It is also important to mention that there is no such thing as writing bug free code, as there will always be some kind of bug, but it's up to you to make it easy for yourself to lower the possibility for bugs to appear.
When I and others advocate against unit tests, it is not because we advocate to running no tests, but rather that you usually want to build up your test sweep with different things than unit tests.
Unit tests are kind of like a small hand shovel. It is a basic tool that you can easily get most people to use, and while you can in principle dig out the foundation of a building with such a tool, there are usually other better tools to do at least the majority of the job. Aside from just taking a ton of work if you use it for testing everything, they also tend to have a lot of other problems when the scale of the system becomes a bit larger, which generally has the effect that you are unable to detect a ton of bugs.
The first main failing point is that composition of bug-free components does not lead to a bug-free system. It is easy to see this by realising that each of the operations you write in your program is expected to be (mostly) bug-free in terms of the programing language, but their composition into a program is expeceted to easily yeild a ton of bugs that are not related to bugs in the components, but rather in how they are combined or assumptions on how each component works.
The second main failing is that it is hard to write unit tests for bugs you did not already anticipate and therefore already considered when you wrote the code. Combine this with that the scale of the units in unit tests are usually so small that you could keep those things in mind, and you will that in a lot of cases you can mostly only test for things you already took an effort to not have as bugs. This means that unless you are uncertain about a unit working, it will mostly not be able to find any significant bugs (mostly it will find typos/grammar problems).
Combined, it means that unit tests are really poor at covering the main areas where you can expect to find significant bugs: at complexity and for things you did not consider.
Another strike against unit tests, is that they are barely ever actually failing after they were written in the first place, and as such does not give that much value in regression testing. The problem here is that tests mainly fail where there are breaking changes in the code covered directly underneath them, but unit tests usually cover such small areas that you rarely need to make significant changes underneath their covered areas, and most changes you make on that level are often written outside those units in some way, such as written in a new function instead, for which the old test does nothing and you will have to make new tests to cover that new thing, and that does not give the same kind of safety as having something covered under already working tests.
There is also the issue of actual coverage of new tests introduced, which means that when someone submits something new, then you would rather know that it was covered by existing tests rather than trust that whatever tests they added are enough to cover all the potential problems with the new thing they introduced. Here I am not talking about line coverage, but coverage of actual possibilities for bugs. This is never going to be 100% with any method, all you can do is try to get the coverage as high as reasonable for the amount of resources you are willing to throw at it, and unit tests and setting up coverage for each unit takes a ton of resources and has a ton of diminishing returns in terms of pushing it higher, because it has a really hard time actually covering a lot of potential bugs.
All of this might make me sound like someone who are fine with leaving tons of bugs in their code, but that is not the case and this is the kind of mentality I used when I set up the ways to keep bug-critical software safe, the kind where bugs are expected to be associated with tens or hundreds of millions of euro/dollars in losses. I just do not trust unit tests to work well enough for that case, and especially not if I had to do the job with a similar amount of effort, as the amount of work to make that many unit tests would have likely costs similarly huge losses due to delays in deployment of the system.
Generally speaking, tons of unit tests are a bit similar to tons of comments, in that they are mostly a sign of an intermediate level, as beginners learn to add comments to explain their things and add (unit) tests to generate trust in the system, but experts instead look to remove most of either by using better and more appropriate tools. For comments it is often about making comments redundant, by simply having the code be self-explainatory, and for tests it is largely about writing fewer more powerful tests. Generally speaking, large scale tests, such as more like intergration and functional tests, tend to form a good basis for your regression test sweep, and for more local areas of complexity things like property based testing can be used to look for unrecognised problems. I personally also like to sometimes do some manual testing of the principles in something before I write the actual code, as this both gives better insight and because it catches the potential bugs earlier also reduces the cost of finding and handling those bugs - also it is less borring, and that is important both for my enjoyment and to keep concentration and work quality high.
Couldn’t agree with all your points more. I have a problem with unit tests not because I don’t want to write them but because they do do a poor job of testing any complex portions. I find good integration tests, functional tests, and end to end tests to be worth their weight in gold
I don't know what point you try to make. Write unit tests but make sure they are powerful unit tests and not meaningless?
Spot on!
@@psychic8872 He basically means, unit tests only tests direct code, no complex code.and adds more noise to the code than it solves and give false sense of bug free. It also hides bugs that unit tests does not cover because you are unaware that it missed something.
I also experienced cases where the unit tests was testing mocking and not the real code. No one knew, because everything was green.
When you are a beginner developer, unit tests will save you, but when you have decades of experience, unit tests are additional noise preventing you to see the real code.
Code can be self tested in the way you construct your code. The code becomes the test itself and you did not waste any time and energy creating unit tests. Instead of 10 lines of unit test code for 1 functional line, you get 10 lines functional code for 1 line of unit test code.
Doing this way you can modify code way faster, without dragging 10.000 uni tests with you that prevents any change in your code.
One example, I just found an error in C# code that unit tests failed to catch.
double valueAsDouble = 3.1
int valueAsInt = (int) (valueAsDouble * 100)
valueAsInt became 3100 in the unit test but in the code somewhere else 3109.
Same project, same compiler, same codebase different outcome but in extreme rare case..
Maybe the only way to write code with no bugs is writing no code at all. Writing tests help to mitigate what we know that could go wrong, but we can't be 100% sure that our code runs perfectly 100% of the time, because we can't know in advance all the contexts of use of each piece of software that we build and we use.
You can't, some other developers can
@@gouryHey there, 10x developer 👋
It’s simple. If you aim for 100 percent bug free code… you might land somewhere in the 90 percent range.
If you just say, what’s the use! The code will always have bugs! Then people stop trying and then the rest should be obvious.
You can know the context because you're writing the function. It's up to you to apply constraints to prevent misuse. Library writing 101.
@@kantancoding Yeah, that's the point. We should aim for the 100% knowing that we did a great job, and tried to prevent all the errors we know that exists or we foresee. The thing is: if we approach the code with the idea that we should write 100% bug-free code, then maybe we're missing the point of writing tests, hence writing no code at all. Tests help to document what we know, not the future.
The thing you're doing in your example, which is also critical, is moving towards referential transparency. Lots of little functions that behave functionally--give them parameters and they return the same value. I don't endorse it universally, but where it adds clarity and testability, referential transparency is always a good thing to move towards.
That also produces code you can more easily eye-test: the less state, the less you're trying to keep track of in your head, the more obvious the bugs.
all this work and you're still saving untrimmed name to the database lol
You must have missed the part where it got fixed 🤔
@@kantancoding you only check if it's empty after trim, nothing prevents from saving " username " to the database
Ah, you’re right! Would need to refactor something and update the tests in that case 👍 but in my defense, it’s not really the point 😂
Indeed, and that was obvious just by looking at it for a moment. Unit tests aren't the cure lol
That's literally the first thing I noticed 😂😂😂
I used to hate writing unit test. Then I joined a team that has no unit tests and a massive monolith where causing a regression bug is not too hard. It's the regression testing for me that has the most value as time goes on.
These three principles 1. aren’t laws 2. aren’t going to stop all bugs: at best tests are heuristics. Look up Dijkstra quote on testing
We should use behavior/micro-workflow texts. Where we don’t test the internals. You are showing how to tests internals
Bad code making it into master/trunk should be caught before going out. Breaking master is fine. Allow self-approvable PR’s and use pair programming for continuous review
Keep working at it. You’ll get there and fix the whole in this video. Great to put something out there
I've catched the Trim issue because I made some stuff in the past that I needed to cut spaces from both sides, and thankfully the Go developers already thought about that
I didn't catch that error, mostly because I know C#, and the name of that function is "Trim", so I thought it looked correct lol
@@jmvrC# trim is so much better than other languages ngl 😂
I cannot stress how useful having a test to document code is.
I have 10 years of experience as a developer.
I can't count the number of times I've been confused as to why a piece of code seems to be going out of its way to do things a certain way but there are no comments or external documentation to explain why and the person in the git blame hasn't worked for the company in 5 years.
This goes one of two ways:
1. I find a unit test that explicitly tests that part of the code and all is clear.
2. I start ripping things out and fooling around with it to see how it breaks. The ✨I ✨add the unit test.
The second takes *a lot* longer
As a non-programmer starting writing some code, this cleared up a lot more than alle the other learning tutorials did. Most talk about the basics, but not on how to write code and hos to use functions. This was very clear and also clear WHY. Thanks!
That’s great to hear! Thanks for watching :)
I catched the suffix one! Not the trimSpace, I don't know Go :D
👁️💯
I didn't believe in unit tests... but then I saw the light... the amount of bugs I have found with unit tests makes it well worth it!!!
People seem to get angry if anybody mentions that unit tests are helpful. But that seems like a personal problem 😂
Writing and sorting unit tests also helps with code that's bug free but does not work as intended. Checking the expected range of variables for >,
I would argue that a bug is something that doesnt work as intended.
@@munchduster2815 For me a bug is an error in the code and can be found by analytics. But there are other reasons why your code does not work as intended:
- the customer communicated a different problem than he actually had
- the problem changed over time
- the problem was not specified correctly
- the customer does not stand the reality check.
Those are all reported as bugs, but may not be solvable in code without altering other aspects of the project like the specification or definition of the problem you are trying to solve.
@@MrHaggyy if the customer communicat d a different problem than they had I agree that isn't related to bugs, but that the program is working as *you the developer intended*. Similar reasoning for the other examples. Those are problems about developing the wrong product because of poor communication.
Just because a user reports something as a bug doesn't mean it's a bug. An extreme example could be that I think Minecraft is too blocky and report that as a bug, that doesn't mean that Minecraft being blocky is a bug, it's completely intentional. Similarly if a was asking a developer to make a voxel game and the outcome was like Minecraft (blocky) and I was expecting not blocky like Astroneer.
(Taking a second to say that although I debate your definition of a bug, I acknowledge that you are identifying issues that happen in real projects around customer requirements and interaction which affect the project beyond just the code written)
You missed the real first law. Write a unit test BEFORE YOU TOUCH the code as a baseline. Even modularizing code can miss subtle requirements that aren’t called out in the code. So write a unit test against the old code FIRST.
Not quite, but the key is that you want to ensure that there are tests to ensure that the functionality and features expected of old code already has tests before you go and make changes to it. Generally though, you want to not be writting new unit tests for this purpose, because tests covering this should have been established long ago and you likely do not understand/remember all the parts that needs to be tested for when you are working on others/old code.
if what is already there is insufficient, you can add in some tests, but unless you already have a good understanding of that piece of code you have to come to terms with it being hard for those tests to properly cover all the things that should be covered with tests.
@@sorcdk2880no better way to come to terms with it than writing tests
The real value of tests, both unit and regression, isn't in finding bugs when they're written. As written they had better pass. Their nominal value is in maintenance, ensuring you haven't screwed something up. Even more valuable than that though - they give you confidence. A good suite of unit tests (for isolated tricky parts) and regression tests (for overall system behaviors) gives you the confidence to clean up your code. Any reasonably complex system is always going to have things you wish you had done better, or knowing what you know now things you'd have done differently. There's a reluctance to do that refactoring and cleanup of tech debt because no-one wants to break a running system. A good suite of tests gives you the confidence to make those clean up / refactor efforts knowing that you're unlikely to quietly break something someplace else. The net effect is your code steadily improves due to those incremental refactors.
Also, naming convention is very important.
Yes! I agree
@@kantancoding I've spent days trying to come up with the right function name and variable names.
Bro is evolving, his edits are and effects are getting stronger 💪🏾💪🏾
Hey bro! Thanks for always supporting!
@@kantancoding please stop evolving and focus on what you're good at.
Everything else is just distracting.
@@kantancodingignore goury
Unit tests catch the easiest kinds of bugs at a cost of a massive test suite that needs to be written and maintained. Unless you're nasa and are going to do every other kind of test under the sun as well you're probably one of those companies that has more lines of test code than production code and yet still ships buggy software. Applying cost benefit analysis and developing in a manner that catches the kinds of bugs that are actually problematic is much more efficient in terms of developer resources. It's a bit of a bold assertion to say that in all circumstances you should write unit tests. Especially with examples like this.
Few people suggest you shouldn't test your code. No one worth listening to does. But people very often have good points and strong arguments for not writing unit tests, especially not by default for every piece of code. Your argument is arrogant and misguided.
Have to respectfully disagree. I don’t work at nasa, I work in fintech and these so called “easy kinds of bugs” (not even sure how you classify a bug as easy. A bug is a bug and can have user impact) scaled to our 100 million + users would be detrimental to our business if core flows are impacted.
@@kantancoding Fintech is another reasonable area to do unit tests, sure enough. But an easy bug is one that is trivial to observe, identify and debug. It's the kind of bug that will be observed and fixed with minimal effort long before shipping without any extra effort. Not all kinds of bugs are equal. Obviously depends on how you ship software and what kind of software you're making. Some bugs are not easy to observe, identify or debug and those tend to be the kind of bugs you really want to invest the time to deal with and those tend to be the kinds of bugs that unit tests won't catch. It's usually at the intersection of units of code and in larger systems that trickier semantic bugs crop up. If you spend all your time wriitng and maintaining suites of unit tests that test things that really aren't complicated you're wasting time that could have been spent finding the important bugs. And yes some bugs are more important than others.
I'm genuinely surprised you wouldn't recognise that not all bugs are equal. Sure I expected you to disagree but it's surprising you would attribute equal weight to all bugs and not recognise that some are trivial to fix and some are extremely difficult to even identify let alone reproduce.
What would you say to people who essentially write unit tests, make sure the code works, then bin them rather than maintain them? I'm sure you'll say thats foolish and regressions and all that. But if you've written some maths code, and now that maths code is working, and you're not going to touch it again, why would it make sense to run tests for that maths code every single time you're building your software? You're slowing the code-debug-execute cycle drastically, adding code to maintain (which itself can have bugs) and for very little benefit (if at all) yet that is what you're arguing for with an authoritarian manner and calling people who have recognised that testing software is more nuanced and that other kinds of testing might be more economical and effective fools.
Not all bugs are equal. Unit testing isn't the only way to test software. What are you, the sith. Do you think you're the sith or something?
I see most comments are already controversal: As a non-professional, hobbyist coder, I have to say most bugs come from complex interaction of different modules, random (invalid input) that you did not foresee (hence could not be put in a unit test) timing issues and race conditions etc. Such unit tests only catch the simplest typos which you would catch already if you just made a few simple tests of your newly written/modified function.
Yes you are right. Testing is a controversial topic. No way around it
I think that it's important to distinguish between different platforms. On mobile for example, having unit tests for non logical functions, is just useless and makes the process longer for no reason. We should learn to adjust our thinking to the platform and scenario which we are coding in
0:10 No, they usually tell me to write unit tests. And I do it when it makes sense. Maybe when I document a library or something.
Good point!
How does that Testing extension work? It looks very useful.
Code is a team sport, adopt and follow the same detailed programing style guide.
Until you land on a bad team. Then you can either join the shit show or try to help them improve.
Unit tests do not guarantee bug-free code. They only guarantee that the code is bug-free in the tested scenarios. It reduces bugs by ~40%.
I'm a front-end developer, I really hate unit testing a component. My other collage is unit testing a component to make sure it renders on browser, to make sure the text is show on dom, why? It really pointless. I rather using E2E for testing the web application (business flow) and ONLY unit-test a PURE FUNCTION (without dom or other shit like that).
Are you saying that unit tests are pointless because E2E tests will have 100% coverage?
Bro factored out a Boolean expression in a function 💀
I belive, that Unit Test is one Excelente Tool ,that every person that write code should learn how to use it.
💯
I'm consulting right now in a company whose culture doesn't understand any of this. This video is correct.
If you find yourself in a place that only does integration tests and thinks 70-80% code coverage is fine. You're in amateur hour. And it's gotten more common in the past few years. Don't worry, they're wrong, and you who will test all the things and write small code are right.
Totally agree. Integration tests are cumbersome and very slow especially if your unit to integration test ratio favors integration tests on large projects.
Many integration tests can actually be refactored to unit tests in my experience.
What font do you use in your code examples? It's beautiful.
Write less bugs by writing your code twice and hoping that one of them is right
I was a 'hater' of unit/integration tests until I had to fix big git conflicts .. h2 and testcontainers really change that for me.
You know what's even better than tests? Type checking.
So the only bugs are segmentation faults 😂
Unless a dependency library uses ANYs
Type checking only really handles one specific category of bugs. The idea that type checking would magically make bugs go away is more of a fever dream. I have written programs in enough different languages with different level ot type checking to know that you still have plenty of potential things that can go wrong even when type is correct. Heck, a lot of those other types of bugs tend to pop up more in languages with very strict types. I see a lot more "off by 1" and problematic recursion conditions in languages like C/C++ and Haskel compared to languages like Python. Of cause if you are living in one of those type nightmares like javascript then the conditions change, but often you have that the flexability of less strict types means you do not have to do so much manual low level manipulation where those other types of bugs tend to pop up.
It builds. Ship it. Lol
@@7th_CAV_Trooper this is how sites break :D
It took me under a minute to spot the suffix thing, without even knowing the language this code is written in (suppose it is Go?).
Wrote ton of code in my life without writing a single unit test and I'm still convinced it is wasted time if you are a good developer.
It can be useful in some corner cases where you have functions that implements particular algorithms, but nothing more than this.
That said, if I need to write them, I can write them. Just, I don't need them.
Great information btw, Kantan. Can you create another video that only covers unit testing? I searched on your channel but didn't find one.
Hey! is there something in particular that you want to see?
@@kantancoding Maybe have some crash coarse on how to write UT for web application or microservices, that would help a lots for beginners T>T
Could you pls do videos on software design patterns usning Go!
Just love the content on object oriented concepts, you made it looks so simple.
What is the dark sound of the background music (starts at law 1 and 2). Thanks!
Well if the dev doesnt find a bug without a test, the CI/CD Pipeline does its job and the reviewer doesnt find it, there is potentially a chance that the customer also won't find it in production.. 😂
Law 0: Rules don't matter when met with reality. The reality is your customer doesn't care about how clean your code it as long as they get to do tasks with as little disturbance as possible.
If I have to go through 20 pop-ups to start using your website. Forget about your "clean code".
This is not enough to make it bug free, but it is sure a good advice.
While there is no proven way (yet) to guarantee nonexistence of bugs, there are few practices that can make the code almost bug free.
Coincidentally, each of these practices include this testing advice as a requirement, but that's just a one tiny part.
I agree that “bug free” isn’t possible. But like you said, we should definitely aim for it!
@@kantancoding it is possible, you just can't prove it (yet)
I have some noobish questions
Should you test for parameter types? I.e. ensure that a function only accepts a certain parameter type?
Do you have to consider all "edge cases"? For example, in the isValidAge function, the critical points are at, below, and above minimum age. But what about 0, 1 or negative age? What about large ages, like 60? 100? 99999999? Is this related to the "business logic" jargon?
I admit I don't write tests at all. I know their value, but I don't know when is a test "good enough".
The questions above, I swear I've tried searching about but I couldn't find a very good reference.
TDD is old but gold process
1:08 , Extracting those things into isolated functions is great for readability and makes reasoning about the code much easier. However, I often come across functions that are untestable because they are private and not available for testing. There might be one public function that calls these five private functions. In such a case, what should you do?
You should always test through the public functions. If you need to test private functions then this is a smell that indicates you should split it up into separate modules instead (e.g. classes if you're using a language with classes)
Even if all imaginable checks are performed, there is no theory, nor metric, nor tool, and particularly no "laws", that can tell us how many important bugs remain. We must test - experiment in an exploratory way - in order to have a chance of finding them. No one can know in advance where the unanticipated bugs will be and therefore what scripts to write. Not denying the value and importance of unit tests, but there are not a silver bullet against bugs in the code as you suggest by the title of your video.
I had kind of expected something much more powerful (and much more restrictive) than what was presented here based on the title.
Unit tests help void somethibg liek segfaults. However in my experience (embedded) there are far more functional bugs that sometimes only get noticed in field tests.
Hey, very nice video, the importance of good tests (unit/integration/feature) is paramount. By the way which font are you using in the video? it looks very nice!
Coolest outro ever
😂
Ok do a regression test often. And... once a test failed what then?
Should I move the constante back into the method for example? Or change the unit test?
You should look at the code and the test to determine which one to change, but it would normally be a regression in the code. You don't just change unit tests to match what the code does, you test for desired behaviour. The only time the test would ever change is if there's a bug in the test code or if the desired behaviour has changed, but usually a test starting to fail after a code change means there's a problem with the code that was changed.
Hey, bro. Edit is great!
Can you please share what softwares and tips are you using to make these edits?
I appreciate it.
I don't understand why you test an abvious thing. Also, do you test your tests?
func test_programing_language_is_working_fine(t *testing.T){
assert.True(t,1+1==2, "expected 1+1 to be 2")
}
Don't even open the pull request unless all your unit tests passed locally first.
TDD is great, it is somewhat hard for game development though
I actually found both bugs, so I dont have to write tests right?
I like using the table design for testing and I was a js Timmy who hated testing
Interesting! Does it take a lot of time to come up with test cases?
@@kantancoding it does take more time and probably has discouraged me from fuller coverage but it feels like better quality test and it was the way I learned so it seems more natural I guess you’d say. But I have found myself trying to make it a creative exercise to make it less painful. Maybe it’s log rocket but some org has a great blog on it. I’m doing it on a personal project so it’s not as deadline critical which offers some grace for this approach but I like it (far as liking testing can go haha)
Keep doing your thing man I really enjoy your channel and attitude towards learning
Fully agree with all 3. But holy shit I'm so envious of people that have tests that execute in 2 seconds. Usual test run at my company is 15 minutes and it sucks when you have some trivial error or even worse if compilation fails after 5+ minutes due to some typo.
That must include integration tests right? Integration tests for the larger services I work on take similar times which is why I advocate for writing unit tests instead of integration tests where possible. Can run thousands of unit tests in less than a minute.
@@kantancoding Lets say that it could be called like that. Code base is gigantic and modules are highly dependent on each other and on top of that everything is tied to hardware on which most tests must be run. So in most cases you need to spin up the whole system to run any tests.
You need to write unit tests and not just integration tests. With a unit test you only test that piece of the system in isolation. Anything external that it touches, such as the database or file system you replace with a mocked version. Trouble is that a lot of legacy code wasn't written in a way that allows you to easily do that. The best way of getting quick testable code is to write the test first and then write the code to make the test pass. That way your code is structured in a way to make it easily testable. Once you start doing that and making your tests small then are well on the way to do Test Driven Design (TDD). This is a mindshift and feels weird at first, but it works. I'm a senior dev with nearly 40 years experience - I found it weird, but I'm now reaping the benefits,
Start moving your legacy code behind interfaces to modularize it. Then you can stub those legacy interfaces and avoid having to spin up real objects when unit testing other units. Even in integration testing, you should never have real versions of code whose functionality is irrelevant to what you are testing. If you do, then you need to make that other functionality independent of the system under test (modularization).
The trick to handling this is to have different options for testing. You typically want at least one way to run tests locally that take less than 10 seconds, and maybe one that can be completed within a few mins. The first of these is used like a mental handwashing that keeps you reasonably sure that the code still mostly works, and enables you to quickly know when you start encountering bugs in your new code. The next is used to be fairly sure that things are fine before you push changes to a place that matter a bit more, such as just before you start writing your pull request/getting ready for a merge. Aside from these you might have a large test that are more throrough for more important steps, such as before pushing something to release, other important places or when merging big changes.
unit tests for functions that can be easily verified by inspection is in fact not a good thing. You don't need to write unit tests for things like "shouldReturnTrueWhenAgeBelowMinimum". Granted its just an example but people watching this will take that at face value and write tests for trivial functions that do not need unit tests. There is no clear guide for what is considered a unit. You risk creating units that are too granular.
edit: also, factoring out code that is both small and never reused is stupid too. Don't pull something out into its own function if its a handful of lines and is never used anywhere else. You're just adding to the call stack for no good reason. Write readable and commented code instead of pulling something out into its own function. If it's a massive chunk of logic or is duplicated, yes factor it out.
And taking that logic further, the only real "unit" that isn't granular is the entire application, and the only test case that encompasses all use cases is production. I.e. test in production.
Seriously though, if you can't write code without bugs then you can't write tests without bugs. Things will break eventually, might as well optimise to allow you to fix it as fast as possible.
@@MarthinusBosman There are countless levels between test in prod and test every minute bit of logic. You should be pragmatic in what you define as a unit.
I agree. And what helps most with fixing as fast as possible is being able to trace through code as easily as possible. Which you make hard by over-modularising your code.
Generally speaking, pulling out a non-repeated function is a readability vs performance choice. Most of the time the trade-off is such that you want the readability over the performance. Generally speaking the purpose is to make it easier to see at a glance what a piece of code does, and how that interacts with surronding logic. This requires one to get to a certain level in the art of naming before it gives much value though, and if you are bad enough at that art it is going to be a net negative in terms of readabilty.
In terms of factoring out really small functions, then I have actually found bugs in other peoples code when I used that to make sense of larger mathematical expressions. Most of the time single operation functions feels kind of weird. Boolean checking is weirdly one of those cases where it often makes sense to do rather banal functions, because the mental gymnastics of translation the mechanics of a boolean check into its purpose in relation to the surronding logic means that grasping the logic of the control flow takes quite a bit more effort.
I as somone who cant do Test, do Tests If possible, im working in a language / envoirement that doesnt Support Tests so 1 Change = deploy to Test system and Test in the normal User UI If the Change worked or step trough Code with Debugger
Luckely our Codebase isnt that large only ~20k lines Source Code +100k lines Translation and Design files
I think there's quite a few problems in this one.
The first example is not a good example of modularisation 😅 simply splitting things into functions does not make code modular. Many would say the code is worse now because it is split up unnecessarily - now there are multiple functions to read instead of just one. Modularisation means decoupling code, which in this example is not what's happening - the implementation jumps across functions, but it is still tightly coupled. And code that is tightly coupled but spread out is actually one of the worst things for maintenance and readability.
Secondly, we should only write unit tests against public interfaces. Writing them against these private implementation details is the road to pain and suffering with brittle tests that need to be rewritten every time something changes. What is shown is not good unit testing practice, and in fact is how many people end up with the false conclusion that unit testing is pointless and painful, because they end up essentially just having to write all their code twice.
I like that we're teaching people about the value of unit testing, and we've got the right idea here with how to avoid regressions, but this is not a great example of how to do it, unfortunately.
Modularization doesn't always have to mean decoupling with an interface and abstracting implementation details.
Like showed in my example, you can test code segments in isolation simply by breaking apart large functions into smaller functions and using DI(Dependency Injection). This is another form of modularization.
The common argument that having "multiple functions to read instead of just one" makes things difficult to understand is not a good argument imo. Like with all things, there's a tradeoff. Needing to jump to function definitions vs needing to resort to writing integration tests to test core logic that doesn't have network dependencies etc.
"Secondly, we should only write unit tests against public interfaces. Writing them against these private implementation details is the road to pain and suffering with brittle tests that need to be rewritten every time something changes."
In response to the above point. Us engineers tend to state our opinions as hard rules. I'm guilty of it too but in actuality this is just your opinion. You say that we should only write unit tests against public interfaces. Public to who? And what examples did I give where the tests test private implementation details? For example, we aren't testing that the TrimSpace method is doing what it is supposed to do. Those are implementation details that are a black box. We are testing that we are using the correct method in our own function.
Admittedly, the examples are oversimplified just so that I can explain the points more clearly and so that people can easily follow along. But for more experienced people, you should be able to replace the oversimplified examples in your mind with more real world examples based on your experience.
Anyways, I've enjoyed your comments on both of my recent videos. They seem well thought out so thank you for taking the time!
@@kantancoding hey I appreciate the response! And I hope I'm coming across as helpful not just negative!
I've extensive experience teaching junior engineers, and like you say the senior engineer understands what you're saying and can contextualise it. The junior engineers cannot, and so what I mean to say is the examples given can lead people astray.
Dependency Injection would absolutely make that code modular in the way it was split - I might be wrong but I don't think DI was mentioned in the video, and this is a key detail here that is often not obvious to juniors.
A similar detail that can cause a misconception is avoiding hard coding the company by extracting to a constant, but the constant is still hard coded - it's just not inside the function any more. Similar to just moving code into another function does not produce modularity, moving a literal to a constant does not remove hard coding. Again, a senior gets that but a junior might not.
Unit testing against a public interface is more than my opinion, it's more or less the only way that unit testing is generally useful 😅 you can test implementation details if you like but you'll just end up writing your code twice every time, which is where many people go wrong with TDD and end up jaded on it. You want to treat your code as a black box, and only this will produce the very real and very powerful positive outcomes you mention in your video.
Public in this sense means where the "seams" in your code are, in other words the public edges of your abstractions. Usually in C# or Java worlds this is an interface, in JavaScript it would be an exported function. If you are exporting a function, or promoting a class member above private just so that your unit tests can see it, this is often an indication that you're testing implementation details.
When you decide what a piece of code does, you encode its contract with the world in the tests you write against it. The tests (like you very rightly pointed out!) then form machine verifiable documentation to others about how to use the code and what it does and does not do.
So in that sense what we mean by public here is what does a caller need to know and care about, and what shouldn't they know and care about? And this is the key art of software design, i.e. choosing useful, meaningful abstractions that effectively modularise your code.
I enjoy your format, and I think you're sharing really good ideas! I do think these kinds of details are important if you are aiming to teach your ideas accurately (based on my own learned experience teaching poorly on many occasions!). I hope it helps!
I see! You make some good points. It’s actually very difficult to fit many details into a short video that people won’t immediately click off of out of boredom so I’m still trying to find the balance of what should be implicit in my explanations and what should be spelled out word for word.
Anyways, your feedback is valuable and well thought out and I really appreciate you taking the time 🙂
no worries at all, I'm glad if it helps
I appreciate that teaching in general is a very tricky thing, and of course throw the constraints of a YT Creator (which I know nothing about) over the top and I imagine it becomes even more difficult! And on top of that you get annoying know-it-all kids in class (like me) who try to correct you!!
I'm very lucky to have had good mentors and teachers, and so I've a huge amount of respect for those engineers, like you, that take on the tough job of guiding others and passing on their skills.
It's definitely less coupled when modular. You should also test internals
I agree with you, but I think that we have more rules
Good point. Which do you think are the most important?
I don't know Golang, so i couldn't recognize the bug.
1) Modular and maintable code (use functions)
2) write Unit tests
3) Write regression Test
Nice video! I have a problem myself writing tests. I can't find the balance between modularity and unit tests. I find myself testing if user click the button the function is called, or if the user fill the email input an email field is sent to the backend. Besides validation logic and empty results, I don't find those tests much useful. How can I write useful tests that are just not checking the default behavior of the programming language?
Yeah this can be a bit difficult with languages that have no type safety. You end up writing a bunch of stupid tests checking if the right type is passed into the function etc.
Basically, I’d try to avoid testing implementation details. What you should test is largely dependent on the application you are working on and what business logic is important to said application.
Try to test individual responsibilities in unit tests. The important part is correctly defining those responsibilities.
The examples in the video are oversimplifications to make the video easier to understand but you should think critically about which parts of your app should be considered their own components based on your particular project.
@@kantancoding thanks for the answer. Yes exactly! I'm looking for content about testing, but every video that I find explain the concept but the examples are oversimplified and I can't find examples of where to draw this line between business logic vs implementation details.
Hey, great video!
As a note, i always try to read the code on screen to get more insight, but I noticed that it sometimes doesn't really represent what you are talking about.
Like in the end the code shown was the original code, with the 2 bugs.
Also I didn't find how the string extraction causes a bug. Is it a go thing?
Yeah that was a mistake! Thanks for catching it. I accidentally did animations/video editing on the old code 🫠
But the code that I ran the regression test for was the updated code!
@@kantancoding Oh I see, no problem
Thanks again for the video :D
Also, can we stop using the word law and bug free arbitrarily.
If you aim for “bug free” code, you will land in a good place even if you never reach the pinnacle 🚀
@kantancoding is technically true, but you shouldn't use the word or term bug free arbitrarily.
And also using the word law. Though I get what you mean.
Someone that aims at bug free code never finishes, because to find out if something is bug free takes infinite work. It is similar nonsense as "shoot for the moon and if you miss you will hit the stars", which only works for people that did not take the thing seriously in the first place.
As a self-taught toad that jumps on the fly-laden keyboard, I feel vindicated. I did this habitually because I thought I was _bad_ at coding and other coders would ridicule me.
_WHO'S LAUGHING NOW!? HA HA HA HA HA! WHO'S LAUGHING NOW!?!??!?_
Eye catching tutorial to be honest 😅 . Keep working on them
This always made me really confused.
If most of my methods connect to a database should I be doing integration tests instead of unit tests?
You would write mocks to simulate the database. The function should handle data, not the db itself.
what programming language do u use in your videos?
In which cases it is worth to write unit tests over integration tests?, in my experience having to use mockups to test things like DB queries usually results in the test not covering really important behaviour, so that kind of test isn't that useful
Since integration tests are resource intensive and slow, I try to write them sparingly.
I worked for a company where the previous devs were a bit too trigger happy with integration tests writing them even where unit tests would have sufficed.
It became a team goal to reduce integration tests 🤣
Nice video but you slipped in this point: testing cannot verify correctness of a piece of software as it cannot prove the absence of bugs, but it can prove the software is wrong (the bug exists). Thats called falsifiability. But it is still very much important: if you try hard enough to prove the bug exists but you fail that means your software is good enough, which is what you need to achieve most of the times (unless you work for NASA or some very critical applications where you need correctness proof). Correctness proof on the other hand is different from testing in a way that it proves the software is indeed correct (no bugs exist). It can be achieved through formal proofs but are very complex and expensive. In 13 years of experience I’ve never had to verify the correctness of a piece of software and most programmers out there will never see or have to deal with it.
Very well explained
I agree with the overall message you're trying to share. But I can't be the only one who shudders at the sight of those function names being entire novels. What the expected return value is can be communicated using comments or even just by reading the code itself. The way you've written the tests is understandable enough: "age = minAge - 1", "isUnderage" and "assert.True" is clear and easy to understand. You write readable code and you do it very well, which makes me not understand the need for such function names. That aside, I enjoyed the video
The long names for tests are actually pretty standard.
It's not so much about the long name as it is about documentation.
A well-tested code-base can contain thousands or even tens of thousands of tests and when the business logic becomes a bit more intricate than these examples you can have multiple failed tests for one seemingly simple change. Being able to read through the test names and understand what their testing without opening each one up to read comments or the code itself saves a lot of time and keeps you from getting distracted from your actual goal of fixing your regression.
Another reason for verbose test names is that a test tends to be more granular than a method would normally be. You could potentially test 10 outcomes for one, let's say 10 line method.
To use one of the tests in the video as an example:
'TestIsBlankStringShouldReturnTrueWhenBlank 'could be shortened to something like 'TestIsBlank'. This would work fine in the video because it's just used as an example, but you would normally test more than just the one outcome. You'd need to test that the method behaves correctly if a null value is passed in or that it does, in fact, return false if the string is not blank and not true as well.
Never mind languages that don't have type safety like javascript where you'd have to check if the method handles integers correctly. What would you call the methods for these tests, considering that 'TestIsBlank' is already in use?
With that said, most test frameworks have a some sort of description feature that would display the description instead of the test name in the test-runner. The descriptions act as a sort of comment.
Sorry for the essay, but there are a lot of intricacies in writing maintainable tests and rather specific reasons for things that look arbitrary or unnecessary. Much like test names, the explanation as to why they are long is also, well, long.
@@markocoetzee6101 Don't worry about it being an essay man, it's well written and informative. I enjoyed reading through it
STOP TURNING YOUR SIMPLE COMPARISONS INTO FUNCTIONS
A simple comparison is much more obvious and clear to read than a random function call
Hii, what color themes did you use??
I didn’t understand what the difference between a unit test and a regression test was. It seems like it's the same thing?
Regression testing isn't an actual unit test, it's more a concept.
If you write some code with a unit test attachted to it, and the test passes, the code works.
If you go ahead and change a small part of the code you just tested, you can not guarantee that the test will still pass. So you would need to rerun the test. When you rerun the test like that it's a regression test. You're testing if the code "regressed" (no longer works).
hope that helps.
A Unit test is about testing a small component in isolation.
An Integration test is about testing multiple components that are coupled (or "integrated") together
A regression test is about running existing tests to ensure that the new code that you have written hasn't broken existing code. A regession test can be either running all the unit tests, running integration tests or even running an end-to-end test. The test is is about "is this change a step forward or a step backwards (i.e a regression)"
Great explanations!
Knatan you're the best
No, you’re the best 🙂
@@kantancoding Thank you
@@kantancoding I liked the OnlyHands joke
okay but why was the last change breaking the test?
The domain name was missing an 'a'
@@AndreLoker thy i thought it was some dumb syntax shit lol
sorry but what programming language is that??
No worries, it’s Go
Well, you should not write too long function names either or your code becomes very bloated.
Keep doing like this bro..Like debugging also
Thanks for the tip bro! Debugging is a good idea
Just found you out
Just watched 3 video
Just subscribed
Here to chill and code 🎉🎉
Welcome brother. Thanks for the support!
I spotted the bugs without pausing
Quality Video!
Is it u it test when I test every single part of lua and progres and make it from start ot beginning constantly checking if it does what it's supsoed to do i til it's finished?
Like I first make it get the height of the character.
Then print the height to see if it's what I expect
Then I continue.
Or did I do something wrong?
I'm self learned programmer and i usualy do it well. It's surprising I got same conclusions and habits you have
When youtube proposed this video on my startpage I was getting ready to comment what's wrong about it, as I have to do with most coding related videos here.
Well, can't do it here. Good work, keep it up.
OK, the title is misleading, though. In order to be "bug-free" you must be able to identify and provide fixtures for all possible scenarios and equivallence classes which may even be impossible or impractical in some cases.
(This means your content is not wrong, it's just incomplete and a bit misleading. However, you were able to deliver the message in less than 4 minutes and youtube doesn't work without a little click bait here and there, so I'll give you a pass on this one ;-))
I've never seen the cigarette.....
😂🤣a true work of art
Thank you
test can have bugs so we must write tests for tests
Great video, short and concise.
But here I'm just doing integration tests these days.
I mean, in the code of the example, the database access part is not tested. Doing mocks for testing is just wrong IMO, so you endup writing integration tests anyway. So I might as well test all the branches of a piece of code in one integration test.
I used to do both unit and integration tests, but really it's not worth. Doing unit tests you endup using mocks, and it can sum up a lot of code at the end, and more code is always a bad thing. Specially in the case of Go, to test with mocks you have to use interfaces. Adding an interface just for the sake of unit testing makes it all more difficult.
Now I don't use interfaces nor mocks, just actual implementations. I use docker to start real components and write a client for my API/service and the tests use this client.
I might write a unit test for a specific function, but for the most part I do integration test and never use mocks anymore.
Thanks for the input! I’m of the mindset that integration tests should be created sparingly. They are resource intensive and slow and when you start to get into the thousands of tests on large code bases, it really starts to slow down the development flow to have integration tests where unit tests would have sufficed imo
@@kantancoding I use ory/dockertest in Go to start the containers during tests. It's fast enough. Once the images are pulled, it takes a couple of seconds to run the tests.
2:52 whoa whats the song 😮
Dope 🙌
My daily exercise and still I'm the only one in the company who writes test 😑
Hang in there!
I found 2 bugs immediately, so now I will never write a unit test again, bye.
Good eye brother!
Your unit test has a bug in it, same shit happens. Your unit test is always going to only be as good as your understanding of the function. And then you might as well just understand the function instead of moving it along
This is why it must be the developer who made the function who covers it with tests.
And if the developer doesn't understand what he's making, he's just not qualified to be a developer.
It is very hard to make a mistake in a test that will make it pass when there is a mistake in the code it is testing.
It is so hard, it have to be done intentionally to work and it is not too hard to spot unless your code is a huge mess.
And if it is a huge mess, that's a reason #0 to reject a PR.
Which is where TDD comes into the picture!
@@ddanielsandberg no it's not.
@@ddanielsandberg you realise when the next developer comes, they'll just update the test as well.
I think you're missing the point I'm trying to make.
It’s actually rare to need to update tests. Usually only happens when some core functionality needs to change which isn’t common in prod applications since usually you’ll be adding features as opposed to altering the present functionality.
What do you mean we don't spot the bug. I mean, idk much this language, and I see some potential errors in it.
How much more to people who know this language.
For any complex system: "Bug free code" in itself cannot be guaranteed. Your title is very misleading.
Unit Tests is not all. Your advice is misleading.
Tests is the requirements we put on the system. They guarantee that those requirements are always upheld.
They do not, however, ensure that your code is bug free, as you could have overlooked or forgot that further requirements also existed.
As long as your thinking is not bug free, there can exist no such thing as bug free code in general.
This is basis knowledge an any CS course. You should know this already.
Nice.
F-ck up enough times and you'll get there. Hopefully without a quarter million cloud service bill
Bro very useful info
❤️
Do people not know what prefixes mean anymore
It’s just an example 😂 next time I’ll get some engineers to review the examples
@@kantancoding Nah I honestly wouldn't be surprised if anyone did actually do that