Software Engineering Stack Exchange is a question and answer site for professionals, academics, and students working within the systems development life cycle. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

Our colleague promotes writing unit tests as actually helping us to refine our design and refactor things, but I do not see how. If I am loading a CSV file and parse it, how is unit test (validating the values in the fields) gonna help me to verify my design? He mentioned coupling and modularity etc. but to me it does not make much sense - but I do not have much theoretical background, though.

That is not the same as the question you marked as duplicate, I would be interested in actual examples how this helps, not just theory saying "it helps". I like the answer below and the comment but I would like to learn more.

share|improve this question
3  
Possible duplicate of Does TDD lead to the good design? – gnat 16 hours ago
3  
The answer below is really all you need to know. Sitting next to those folks who write aggregate-root dependency-injected factory factory factories all day long is a guy who quietly writes simple code against unit tests that functions correctly, is easy to verify, and is already documented. – Robert Harvey 16 hours ago
2  
@gnat doing unit testing does not automatically imply TDD, it's a different question – Joppe 15 hours ago
7  
"unit test (validating the values in the fields)" - you appear to be conflating unit tests with input validation. – jonrsharpe 15 hours ago
    
Not completely on-topic, but one of the reasons I believe in the unit testing is that well-written unit tests are documentation. Especially in behavioral testing, each test has a brief human-readable description of one of the features of the unit under test, and the test itself shows an example of how to invoke that behavior and describes the behavior in an objective, mathematically precise form. And unlike other documentation, the unit tests are almost guaranteed to accurately reflect the code they describe, even as that code undergoes changes over long periods of time. – Kevin 9 hours ago

The great thing about unit tests is they allow you to use your code how other programmers will use your code.

If your code is awkward to unit test, then it's probably going to be awkward to use. If you can't inject dependencies without jumping through hoops, then your code is probably going to be inflexible to use. And if you need to spend a lot of time setting up data or figuring out what order to do things in, your code under test probably has too much coupling and is going to be a pain to work with.

share|improve this answer
    
And if you have to mock a lot of things, then probably the cohesion is low. – user970696 16 hours ago
    
"figuring out what order to do things in" This, this is the bane of my existence. Thank you for pointing it out. – Ivan 14 hours ago
3  
Great answer. I always like to think of my tests as the first client of the code; if it's painful to write the tests, it will be painful to write code that consumes the API or whatever that I'm developing. – Stephen Byrne 12 hours ago
9  
In my experience, most unit tests do not "use your code how other programmers will use your code.". They use your code as unit tests will use the code. True, they will reveal many serious flaws. But an API that is designed for unit-testing may not be the API that is most suitable for general use. Simplistically written unit tests often require the underlying code to expose too many internals. Again, based on my experience - would be interested in hearing how you handled this. (See my answer below) – user949300 10 hours ago
2  
@user949300 - I'm not a big believer in test first. My answer is based on the idea of code (and certainly design) first. APIs shouldn't be designed for unit-testing, they should be designed for your customer. Unit-tests help approximate your customer, but they're a tool. They're there to serve you, not vice versa. And they're certainly not going to stop you from making crappy code. – Telastyn 10 hours ago

It took me quite a while to realize, but the real benefit of doing test driven development (using unit tests) is that you have to do the API design up front!

A typical approach to development is to first figure out how to solve a given problem, and with that knowledge and initial implementation design some way to invoke your solution. This may give some rather interesting results.

When doing TDD you have to as the very first write the code that will use your solution. Input parameters, and expected output so you can ensure it is right. That in turn require you to figure out what you actually need to have it do, so you can create meaningful tests. Then and only then do you implement the solution. It is also my experience that when you know exactly what your code is supposed to achieve, it becomes clearer.

Then, after implementation unit tests help you ensuring that refactoring doesn't break functionality, and provide documentation on how to use your code (which you know is right as the test passed!). But these are secondary - the greatest benefit is the mindset in creating the code in the first place.

share|improve this answer

Unit test allow you to see how the interfaces between functions work, and often gives you insight as to how to improve both the local design and the overall design. Furthermore if you develop your unit tests while developing your code, you have a ready made regression test suite. It doesn't matter if you are developing a UI or a backend library.

Once the program is developed (with unit tests), as bugs are uncovered, you can add tests to confirm that the bugs are fixed.

I use TDD for some of my projects. I put a great deal of effort in crafting examples that I pull from textbooks or from papers that are considered correct, and test the code I am developing using these example. Any misunderstandings I have concerning the methods become very apparent.

I tend to be a bit looser than some of my colleagues, as I don't care if the code is written first or the test is written first.

share|improve this answer
    
That is a great answer to me. Would you mind to put a few examples, e.g. one for each case (when you get insight to design etc.). – User039402 15 hours ago

When you want to unit test your parser detecting value delimiting properly you may want to pass it one line from a csv file. To make your test direct and short you may want to test it through one method that accepts one line.

This will automatically make you separate the reading of lines from reading individual values.

On another level you may not want to put all sorts of physical CVS files in your testing project but do something more readable, just declaring a big CVS string inside your test to improve readability and the intent of the test. This will lead you to decouple your parser from any I/O which you'd do elsewhere.

Just a basic example, just start practicing it, you'll feel the magic at some point (I have).

share|improve this answer

Put simply, writing unit tests help expose flaws in your code.

This spectacular guide to writing testable code, written by Jonathan Wolter, Russ Ruffer, and Miško Hevery, contains numerous examples of how flaws in code inhibit testing. Thus, if you code is testable, it is easier to use. Most of the "morals" are ridiculously simple tips that vastly improve code design (Dependency Injection FTW).

For example: It is very difficult to test if the method computeStuff operates properly when the cache starts evicting stuff. This is because you have to manually add crap to the cache until the "bigCache" is almost full.

public OopsIHardcoded {

   Cache cacheOfExpensiveComputations;

   OopsIHardcoded() {
       this.cacheOfExpensiveComputation = buildBigCache();
   }

   ExpensiveValue computeStuff() {
      //DOES THIS WORK CORRECTLY WHEN CACHE EVICTS DATA?
   }
}

However, when we use dependency injection it is far easier to test if the method computeStuff operates properly when the cache starts evicting stuff. All we do is create a test in where we call new HereIUseDI(buildSmallCache()); Notice, we have more nuanced control of the object and it pays dividends immediately.

public HereIUseDI {

   Cache cacheOfExpensiveComputations;

   HereIUseDI(Cache cache) {
       this.cacheOfExpensiveComputation = cache;
   }

   ExpensiveValue computeStuff() {
      //DOES THIS WORK CORRECTLY WHEN CACHE EVICTS DATA?
   }
}

Similar benefits can be had when our code requires data that is usually held in a database...just pass in EXACTLY the data you need.

share|improve this answer
1  
Honestly, I am not sure how you mean the example. How does the method computeStuff relate to the cache? – user970696 13 hours ago

I would agree 100% that unit tests help "helps us to refine our design and refactor things".

I'm of two minds on whether they help you do the initial design. Yes, they reveal obvious flaws, and do force you to think about "how can I make the code testable"? This should lead to fewer side-effects, easier configuration and setups, etc.

However, in my experience, overly simplistic unit tests, written before you really understand what the design should be, (admittedly, that's an exaggeration of hard-core TDD, but too often coders write a test before they think much) often lead to anemic domain models which expose too many internals.

My experience with TDD was several years ago, so I'm interested in hearing what newer techniques might help in writing tests that do not bias the underlying design too much. Thanks.

share|improve this answer

The real benefit that I see in unit testing for design (particularly in a test-first approach) is that it drives out natural abstractions, which helps to promote modularity (single-responsibility principle), which in turn creates an environment where it's easy to change behaviour by adding and removing things instead of always having to change (and retest) behaviour of existing units.

When you write a new unit of code test-first, you begin with a single scenario - the simplest stepping stone of input/output behaviour you can conceive to test.

What happens, then, is any assumptions you make about the conditions you are testing are naturally pushed to dependencies ("I don't care how this happened yet, I am just assuming it did").

The net effect of this tends to be a very well-abstracted codebase with a very clean separation of concerns and good interface segregation.

Of course, since you write the test first, it also produces more testable code.

My personal experience of using test-first TDD as my standard approach to programming is that it has had an enormously positive impact on the quality of code I write - not because my code is well-tested (though that is certainly true) - but because it actually makes it much easier to write good code in the first place.

share|improve this answer

I've found unit tests to be most valuable for facilitating longer-term maintenance of a project. When I come back to a project after months and don't remember much of the details, running tests keeps me from breaking things.

share|improve this answer
1  
That is certainly an important aspect of tests, but doesn't really answer the question (which is not why test are good, but how they influence design). – Hulk 2 hours ago

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.