Hot answers tagged

256

There are two things you can test in difficult-to-test code. First, the degenerate cases. What happens if you have no elements in your task array, or only one, or two but one is past the due date, etc. Anything that is simpler than your real problem, but still reasonable to calculate manually. The second is the sanity checks. These are the checks you do ...


243

If I have a fairly complex object with a complex method, and I write my test and the bare minimum to make it pass (after it first fails, Red). When do I go back and write the real code? And how much real code do I write before I retest? I'm guessing that last one is more intuition. You don't "go back" and write "real code". It's all real code. What ...


197

That's ridiculous. TDD forces code to pass tests and forces all code to have some tests around it. It doesn't prevent your consumers from incorrectly calling code, nor does it magically prevent programmers missing test cases. No methodology can force users to use code correctly. There is a slight argument to be made that if you perfectly did TDD you would ...


191

Yes, with 100% coverage you will write some tests you don't need. Unfortunately, the only reliable way to determine which tests you don't need is to write all of them, then wait 10 years or so to see which ones never failed. Maintaining a lot of tests is not usually problematic. Many teams have automated integration and system tests on top of 100% unit ...


140

I am a part-time programming teacher at a local community college. The first course that is taught at this college is Java Programming and Algorithms. This is a course that starts with basic loops and conditions, and ends with inheritance, polymorphism and an introduction to collections. All in one semester, to students who have never written a line of ...


123

In regard to the common definition of unit tests, I'd say no. I've seen simple code made convoluted because of the need to twist it to suit the testing framework (eg. interfaces and IoC everywhere making things difficult to follow through layers of interface calls and data that should be obvious passed in by magic). Given the choice between code that is easy ...


119

Should savePeople() be unit tested? Yes. You aren't testing that dataStore.savePerson works, or that the db connection works, or even that the foreach works. You are testing that savePeople fulfills the promise it makes through its contract. Imagine this scenario: someone does a big refactor of the code base, and accidentally removes the forEach part of the ...


101

First of all, we have to fundamentally distinguish between Computer Science and Software Engineering. (And maybe to a lesser extent between Software Engineering and Programming or "Coding".) As one of my CS professors put it: if you need a keyboard, you are not doing CS. TDD is very much a Software Engineering practice. It doesn't really have much relation ...


86

Software is not a house. Intuition is good, but understand that it isn't always correct. Break down all the specs into inspection I think I will need (see into the future). This isn't accurate. In TDD, you're describing how you want to use the code. The specs say "There must be a house, with a way to enter it." The test then says "Hey, I want to have a ...


83

One of the benefits of a TDD approach is only realised when you also do emergent design. So in your first analogy, you wouldn't write 100 tests, as there's no possible way that you'll know what your software will look like. You write one test. You run it. It fails. You write the smallest unit of code to make your test pass. Then you run your test again. It ...


81

I used to write tests for scientific software with difficult-to-predict outputs. We made a lot of use of Metamorphic Relations. Essentially there are things you know about how your software should behave even if you don't know exact numerical outputs. A possible example for your case: if you decrease the amount of work you can do each day then the total ...


78

Regression testing It's all about regression testing. Imagine the next developer looking at your method and noticing that you are using magical numbers. He was told that magical numbers are evil, so he creates two constants, one for the number two, the other one for the number three—there is nothing wrong in doing this change; it's not like he was ...


77

If you have worked on large code bases created using Test Driven Development, you would already know there can be such a thing as too many unit tests. In some cases, most of the development effort consists of updating low-quality tests that would be best implemented as invariant, precondition, and postcondition checks in the relevant classes, at run-time (i....


71

Boring structural code doesn’t need isolated testing. Test interesting code. That code has a behavior. Nail down the behavior you expect and not only will your code likely be correct, it’ll be easier to read. But keep that interesting code away from the boring structural code. Do that and I’ll be able to read it and trust it without a test that isolates it. ...


69

Is writing testable code still good practice even in the absence of tests? First things first, an absence of tests is a way bigger issue than your code being testable or not. Not having unit tests means you're not done with your code/feature. That out of the way, I wouldn't say that it's important to write testable code - it's important to write flexible ...


66

A lot of people think that unit testing is method-based; it's not. It should be based around the smallest unit that makes sense. For most things this means the class is what you should be testing as a whole entity. Not individual methods on it. Now obviously you will be calling methods on the class, but you should be thinking of the tests as applying to ...


66

You're worrying about implementation details too much. It doesn't matter that in your current implementation, isEmpty relies on count (or whatever other relationships you might have): all you should be caring about is the public interface. For example, you can have three tests: That a newly initialized object has count == 0. That a newly initialized object ...


60

The red green refactor cycle is built on one very sound principle: Only trust tests that you have seen both pass and fail. Yes that works with automated integration tests as well. Also manual tests. Heck, it works on car battery testers. This is how you test the test. Some think of unit tests as covering the smallest thing that can be tested. Some think ...


60

This answer consists of two separate views on the same issue, as this isn't a "right vs wrong" scenario, but rather a broad spectrum where you can approach it the way it's most appropriate for your scenario. Also note that I'm not focusing on the distinction between a fake, mock and stub. That's a test implementation detail unrelated to the purpose ...


56

TDD is a nice process in "real-world" programming because problems often arrive on our desks underspecified. "Add a feature that does X", "fix the bug where it shows the wrong thing if you do Y", etc. TDD forces us to create a spec before we begin programming. In CS/programming classes, the problems usually come to us extremely well-specified. "Write a ...


52

TDD is used mainly (1) to ensure coverage, (2) and to drive maintainable, understandable, testable design. If you don't use TDD, you don't get guaranteed code coverage. But that in no way means that you should abandon that goal and blithely live on with 0% coverage. Regression tests were invented for a reason. The reason is that in the long run, they save ...


52

In TDD, the tests serve as executable documentation of your design. Your design changed, so obviously, your documentation must, too! Note that, in TDD, the only way in which the attack method could have appeared, is as the result of making a failing test pass. Which means, attack is being tested by some other test. Which means that indirectly receiveAttack ...


50

The answer is yes, you should write them and you should run them. Your testing framework needs a category of "known failing tests" and you should mark these tests as falling into that category. How you do that depends on the framework. Curiously, a failing test that suddenly passes can be just as interesting as a passing test that unexpectedly fails.


50

1) Do we need to log if we are doing TDD? won't a failing test reveal what wrong with the application? That assumes you have every possible test your application needs, which is rarely true. Logs help you track down bugs you did not write tests for yet. 2) Should we add test for the logging process in each method in each class? If the logger itself is ...


50

The fact that your data-gathering methods are complex enough to merit tests and separate enough from your primary goal to be methods of their own rather than part of some loop points to the solution: make these methods not private, but members of some other class that provides gathering/filtering/tabulating functionality. Then you write tests for the dumb ...


50

Yes, it is good practice. The reason is that testability is not for the sake of tests. It is for the sake of clarity and understandability that it brings with it. Nobody cares about the tests themselves. It is a sad fact of life that we need large regression test suites because we're not brilliant enough to write perfect code without constantly checking our ...


50

Testing before and after In TDD, should I add unit tests to refactored code? "refactored code" implies you are adding the tests after you've refactored. This is missing the point of testing your changes. TDD very much relies on testing before and after implementing/refactoring/fixing code. If you can prove that the unit test outcomes are the same ...


47

Refactoring is cleaning up a piece of code (e.g. improving the style, design, or algorithms), without changing (externally visible) behavior. You write tests not to make sure that the code before and after refactoring is the same, instead you write tests as an indicator that your application before and after refactoring behaves the same: The new code is ...


47

The "real" code is the code you write to make your test pass. Really. It's that simple. When people talk about writing the bare minimum to make the test green, that just means that your real code should follow the YAGNI principle. The idea of the refactor step is just to clean up what you've written once you're happy that it meets the requirements. So ...


47

Microtests can help lead to good design. By writing good small tests, you are deliberately testing a small amount of code and filling in its gaps with mock objects. This leads to low coupling (things aren't reliant on each other) and high cohesion (things that belong together stay together). That way, when you go back and make changes, it's easy to find what ...


Only top voted, non community-wiki answers of a minimum length are eligible