views:

1239

answers:

13

I read a lot of posts the convinced me I should start writing unit test, I also started to use dependency injection (Unity) for the mater of easier mocking, but I'm still not quite sure on what stage I should start writing the unit tests and mocks, and how or where to start.

Would the preferred way be writing the unit tests before the methods as described in the TDD methodology?

Is there any different methodology or manner for unit testing?

+2  A: 

Steve Sanderson has a great writeup on TDD best practices.

http://feeds.codeville.net/~r/SteveCodeville/~3/DWmOM3O0M2s/

Also, there's a great set of tutorials for doing an ASP.net mvc project that discusses a lot TDD principles (if you don't mind learning ASP.net MVC along the way) http://www.asp.net/learn/mvc-videos/ Look for the "Storefront" series at the bottom of the page.

MOQ seems to be the hot mocking framework lately, you may want to look into that as well

In summary, try to write a test to validate something you'r trying to archive, then implement the code to make it work.

The pattern is known as Red - Green - Refactor. Also do your best to minimize dependencies so that your tests can focus on one component.

Personally, I use Visual Studio Unit Tests. I'm not a hardcore TDD developer, but what i like to do is this:

  1. Create a new project and define a few of the fundamental classes based on the system design (that way I can at least get some intellisense)
  2. create a unit tests project and start writing unit tests to satisfy the functionality i'm trying to implement.
  3. Make them fail
  4. Make them pass (implement)
  5. Refactor
  6. Repeat, try to make the test more stringent or create more tests until i feel its solid.

I also feel its very useful to add functionality onto an exiting code base. If you want to add some new feature, first create the unit test for what you want to add, step through the code to see what you have to change, then go through the TDD process.

TJB
Thanks @TJB, I'm quite familiar with ASP.NET MVC, I downloaded the Oxite project that seems to be a bit complicated and has use of injection dependency and unit testing. Is that a good example for learning?
CD
Haven't checked out the oxite source, but its just that MVC lends itself to TDD and that 'storefront' video series involves a developer walking through a complete project all with a TDD perspective. Rob Conery claims that he's pretty much learning how to really apply TDD so he leans the best practices, what is practical and when you can compromise. For me, i just use visual studio test projects as my platform. I recommend the sanderson article, succinct and great points.
TJB
Funny you should mention Rob. Oxite was/is considered an utter failure as far as sample apps go. Rob was brought onto the project to try and improve things. I don't think he accomplished his task, but read his thoughts for yourself. http://blog.wekeroad.com/blog/some-thoughts-on-oxite/
Ty
+7  A: 

If you are curious about unit testing the best way to learn it is try it. You will probably start writing integration tests at first, but that is fine. When they seem too difficult to maintain or too much work to write, read more about what kind of tests there are (unit, functional, integration) and try to learn the difference.

If you are interested in starting with TDD, Uncle Bob is a good source. Particalulary this.

More on unit testing

Ensure that you get consistent test results. Running the same test repeatedly should return the same results consistently.

The tests should not require configuration.

Testing order should not matter. This means partial test runs can work correctly. Also, if you keep this design philosophy in mind, it will likely aid in your test creation.

Remember that any testing is better than no testing. The difficulty can be found in writing good clean unit tests that promote ease of creation and maintenance. The more difficult the testing framework, the more opposition there will be to employing it. Testing is your friend.

Ty
A: 

Read Pragmatic Unit Testing in C# with NUnit. It has comprehensive information about starting writing testes and structuring the code to make it more unit testing friendly.

TheVillageIdiot
I bought that book and I've read it a number of times, and it all sounds good in theory, but when it comes down to actually doing it: all of the examples and suggestions are far too trivial when trying to apply them to a real codebase. It's a great book to figure out what Unit Testing is and all of the genralities, but it's hardly comprehensive.
SnOrfus
The examples are perhaps 'trivial' compared to 'real' code, but it helps the book maintain a focus. It was the first thing I read when I was new to unit testing, but it gave me enough ammo to find a load of bugs in my code.
Mark Simpson
I haven't read the book, so I don't know /how/ trivial the examples in it might be, but the key to good design usually is to turn 'real' code into trivial code. That might require splitting classes into much smaller units than you are used to. Good, testable code often causes you to think "can it really do that? a child could understand this code!" because each unit in itself just covers are very limited purpose and is implemented by the simplest means possible.
Cygon
+6  A: 

Yes, the preferred way of doing TDD is to write the test first (as implied by the name Test-Driven Development). When you start out with TDD it can be hard to know where to start writing the tests, so I would suggest to be pragmatic about it. After all, the most important part of our job is about delivering working code, not so much how the code was crafted.

So you can start by writing tests for existing code. Once you get a hang of how the unit tests are structured, which ones that seem to do a good job and which ones that seem not so god, then you will find it easier to dive more into the test-first approach. I have found that I write tests first to a greater extent as time goes by. It simply becomes more natural with increased experience.

Fredrik Mörk
Actually I would recommend against starting to write tests for existing code first if you want to learn TDD. Writing tests for existing code (that have no tests) is often much more difficult (since it was not written with testability in mind) than writing tests for completely new code. Once you master TDD for new code you're well prepared to take on old code with no tests.
Cellfish
@Cellfish: I agree that it can be harder to write good tests for existing code, but it may give you a clear starting point, and you will gain a lot of knowledge about how to structure your future code and unit tests. It's like when people (before the digital era) suggested which camera to get for a beginning photographer: some would advise "get a fully mechanical one and learn all about shutter speed and aperture values; then you will have full control", while others said "get a fully automatic one and focus on the images". Both advises worked, but for different people.
Fredrik Mörk
I am learning TDD and for that I am trying it with a running one. Refactoring the code to support Unit testing and writing them as I go. For the new features of the projects I am creating tests first then writing the logic.
Tanmoy
Nothing makes you appreciate well designed, loosely coupled code more than trying to write tests for code that is fundamentally untestable. Unfortunately, nothing makes you punch yourself in the face more, either.
Mark Simpson
@Fredrik Mörk: I see it as both approaches work for different goals. The techniques used to get legacy code (i.e. code with no tests) under test are slightly different (there is a big overlap but working with old code is "dirtier" I think). So even though it gives you a clear starting point it might not be the best way to start learning TDD. But if you're going to be wriring tests for legacy code for the next few years, then maybe that's where you want to start.
Cellfish
+1  A: 

If you haven't written unit tests before, then just pick some classes and begin to write your unit tests, and continue to work on developing more unit tests.

As you gain experience you can then begin to mock out the database for example, by using the Unity framework, but, I would suggest starting simply and gaining experience before making this leap.

Once you are comfortable with how to write unit tests, then you can try doing TDD.

James Black
+4  A: 

In C# and with visual studio I find following procedure very helpful:

  1. Think! Make a small upfront design. You need to have a clear picture what classes you need and how objects should relate with each other. Concentrate only on one class/object (the class/object you want to implement) and one relationship. Otherwise you end up with a too heavyweight design. I often end up with multiple sketches (only a few boxes and arrows) on a spare sheet of paper.

  2. Create the class in the production code and name it appropriately.

  3. Pick one behaviour of the class you want to implement and create a method stub for it. With visual studio creating empty method stubs is a piece of cake.

  4. Write a test for it. Therefor you will need to initialize that object, call the method and make an assert to verify the result. In the easiest case the assertion requires another method stub or a property in the production code.

  5. Compile and let the test runner show you the red bar!

  6. Code the required behavior in the production code to see the green bar appear.

  7. Move to the next behaviour.

For this procedure two things are very important:

  • You need a clear picture what you want and how the class/object should look like. At least spend some time one it.
  • Think about behaviours of the class/object. This will make the tests and the production code behaviour-centric, which is a very natural approach to think about classes/objects.

Test first or not test first?

I find it usually harder to retrofitting tests to existing production code. In most cases this is due to tangled dependencies to other objects, when the object which is under test needs to be initialized. TDD usually avoids this, because you want to initialize the object in the test cases with less effort as possible. This will result to a very loose coupling.

When I retrofit tests, the must cumbersome job is the task of initializing the object under test. Also the assertions may be a lot of work because of tangled dependencies. For this you will need to change the production code and break dependencies. By using dependency injection properly this should not be an issue.

Theo Lenndorff
A: 

I prefer KentBeck's approach which is nicely explained in the book, Test Driven Development by Example - Kent Beck.

from your question i can infer you are not sure with the test frame work - choosing the correct test frame work is very important for TDD or writing unit tests(in general).

Only practical problem with TDD is "Refactoring"(we need to refactor test code as well) takes lot of time.

FL4SOF
+2  A: 

Choose a small non-critical application and implement it using TDD. At first the new way of thinking will feel weird, but maybe after a week or two practice it fill feel natural.

Here is a tutorial application (in branch "tutorial") that shows what kinds of tests to write. In that tutorial you write code to pass the predefined test cases, so that you get into the rhythm, and later you then write your own tests. The README file contains instructions. It's written in Java, but you can easily adapt it to C#.

Esko Luontola
+9  A: 

Test first / test after:

It should be noted that 'test first' as part of TDD is just as much (if not more) to do with design as it is to do with unit testing. It's a software development technique in its own right -- writing the tests results in a constant refining of the design.

On a separate note: If there is one significant advantage to TDD from a pure unit testing perspective, it is that it is much harder (though not impossible) to write a test that's wrong when doing TDD. If you write the test beforehand, it should always fail because the logic required to make the test pass does not yet exist. If you write the test afterwards, the logic should be there, but if the test is bugged or is testing the wrong thing, it may pass regardless.

I.e. if you write a bad test before, you may get a green light when you expect a red (so you know the test is bad). If you write a bad test afterwards, you will get a green light when you expected a green (unaware of the bad test).

Books

The pragmatic unit testing book is well worth a look, as is Roy Osherove's "The Art of Unit Testing". The pragmatic book is more narrowly focussed on the different types of test inputs you can try to find bugs, whereas TAOUT covers a wider spread of topics such as test doubles, strategies, maintainability etc. Either book is good; it depends what you want from it.

Also, here's a link to a talk Roy Osherove did on unit testing. It's worth a watch (so are some of the test review videos he recorded, as he points out various problems and dos/don'ts along with reasons why).

How to start

There's nothing better than writing code. Find a fairly simple class that doesn't reference much else. Then, start writing some tests.

Always ask yourself "what do I want to try and prove with this test?" before you write it, then give it a decent name (usually involving the method being called, the scenario and the expected result, e.g. on a stack: "Pop WhenStackIsEmpty ThrowsException").

Think of all the inputs you can throw at it, different combinations of methods that may yield interesting results and so forth.

Mark Simpson
+1  A: 

I have worked for companies which take unit testing/integration testing too far and those that do too little so I like to think I have a good balance between the two.

I would recommend TDD - Test Driven Development. This ensures you have good coverage but it also keeps focusing your attention on the right place and problem.

So the first thing you do for every piece of new development is write a unit test - even if you don't have a single class to test.

Think about what you are testing. Now run the test. Why wouldn't it compile? Because you need classA. Create the class and run the test. Why doesn't it compile? Because it doesn't have methodA. Write method one and run unit test again. Why does the test fail? Because methodA isn't implemented. Implement methodA and run test. Why does it fail? Because methodA doesn't return the correct expected value...etc

You continue like this writing unit tests as you develop and then eventually the test will pass and the piece of functionality will be complete.

TheLearner
+1  A: 

I would take on TDD, test-first development, before mocks and dependency injection. To be sure, mocks can help you better isolate your units - and thus do better unit testing - but to my mind, mocking and DI are more advanced concepts that can interfere with the clarity of just writing your tests first.

Mocks, and DI, have their place; they're good tools to have in your toolbox. But they take some sophistication, a more advanced understanding, than the typical testing neophyte has. Writing your tests first, however, is exactly as simple as it sounds. So it's easier to take on, and it's powerful all by itself (without mocks and DI). You'll get earlier, easier wins by writing mock-free tests first, than by trying to begin with mocks, and TDD, and DI all at once.

Start with test-first; when you are very comfortable with it, and when your code is telling you you need mocks, then take on mocks.

Carl Manaster
A: 

I think Dave Astels' book is still one of the best introductions. It's for Java, but you should be able to translate.

Steve Freeman
A: 

Extending on Steve Freeman's answer: Dave Astel's book is called "Test-driven Development - A practical guide". If the kind of application you're writing is a GUI application then this should be helpful. I read Kent Becks' book but I couldn't figure out how to start a project with TDD. Astel's book test-drives a complete non-trivial GUI application from start to finish using stories. It helped me a lot to acutally start with TDD, it showed me where and how to start.