Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

I am just getting started with unit testing but I am not sure if I really understand the point of it all. I read tutorials and books on it all, but I just have two quick questions:

  1. I thought the purpose of unit testing is to test code we actually wrote. However, to me it seems that in order to just be able to run the test, we have to alter the original code, at which point we are not really testing the code we wrote but rather the code we wrote for testing.

  2. Most of our codes rely on external sources. Upon refactoring our code however, even it would break the original code, our tests still would run just fine, since the external sources are just muck-ups inside our test cases. Doesn't it defeat the purpose of unit testing?

Sorry if I sound dumb here, but I thought someone could enlighten me a bit.

Thanks in advance.

share|improve this question
add comment

migrated from stackoverflow.com Nov 22 '11 at 7:24

This question came from our site for professional and enthusiast programmers.

5 Answers

My 0.02$... this is a bit subjective, so take with a grain of salt, but hopefully it'll get you thinking and/or spark some dialog:

  1. The primary purpose of unit testing to me is to ensure that the code that you wrote fulfills the contracts and edge cases your code is intended to fulfill. With unit tests in place, you can better ensure that when you (or someone else in the future) refactors your code, any external consumers of your code should remain unaffected if you have proper state coverage. (at least to the degree that you intend for them to be unaffected).

    In the majority of cases you should be able to write code that can both be shipped to production and is easily unit-testable. A good place to start may be to look into Dependency Injection patterns and frameworks. (Or other philosophies for your language / platform of choice).

  2. It is correct that external implementations could affect your code. However ensuring that your code works correctly as part of a larger system is a function of integration testing. (Which could also be automated with varying degrees of effort).

    Ideally your code should only rely upon the API contracts of any 3rd party components which would mean that so long as your mocks fulfill the correct API your unit tests still provide value.

    That said I'll readily admit that there have been times where I did forgo unit testing in favor of integration testing alone, but that has been only cases where my code had to interact so profusely with 3rd party components with poorly documented APIs. (i.e. the exception rather than the rule).

share|improve this answer
add comment
  1. Try writing your tests first. That way, you will have a solid base for the behaviour of your code and your test becomes a contract for the required behaviour of your code. Thus, changing the code to pass the test becomes "changing the code to fulfill the contract proposed by the test" instead of "changing the code to pass the test".
  2. Well, be careful about the difference between stubs and mocks. Being unaffected by any changes in the code is characteristic behaviour of stubs, but not mocks. Lets start with the definition of the mock:

    A Mock object replaces a real object under test conditions, and allows verifying the calls (interactions) against itself as part of a system or unit test.

    -The Art of Unit Testing

Basically, your mocks should check for the required behaviour of your interactions. Thus, if your interaction with the database fails after a refactoring, your test using the mock should also fail. This of course has limitations, but with careful planning your mocks will do much more than just "sitting there" and it won't "defeat the purpose of unit testing".

share|improve this answer
add comment

Some clever guy said "If it's hard to test, is is probably bad code". Thats why it is not a bad thing to rewrite code, to be able to unittest it. Code with external dependencies is VERY HARD to test, it represents a risc to the code, and should be avoided whereever possible, and concentrated in integration specific areas of your code, fx. facade/gateway type classes. This will make a change in the external component much easier to cope with.

share|improve this answer
add comment

It sounds like you have a monolithic app that does everything in void main(), from database access down to output generation. There are several steps here before you can begin proper unit testing.

1) Find a piece of code that's been written / copy-pasted more than one time. Even if it's just string fullName = firstName + " " + lastName. Break that into a method, like:

private static string GetFullName (firstName, lastName)
{
    return firstName + " " + lastName;
}

Now you have a unit-testable piece of code, however trivial it may be. Write a unit test for it. Rinse and repeat this process. You'll eventually end up with a load of logically-grouped methods, and you're able to extract a number of classes out of it. Most of these classes will be testable.

As a bonus, once you have multiple classes extracted, you can extract interfaces from them and update your program to talk to interfaces instead of the objects themselves. At that point, you're able to use a mocking / stubbing framework (or even your own hand-rolled fakes) without changing the program at all. This comes in very handy once you've extracted the database queries into a class (or many) because now you can fake up the data that the query should return.

share|improve this answer
add comment

Asking a good question isn't dumb in any way.

I'll address your questions.

  1. The purpose of unit-testing is not to test the code you already wrote. It has no notion of time. Only in TDD you're supposed to test-first, but that doesn't strictly apply to any kind of unit-testing. The point is to be able to automatically and efficiently test your program in the class-level. You do what you need to do in order to get there, even if it means changing the code. And let me tell you a secret - it often means that.
  2. When you write a test you have 2 primary options to help ensure your test is correct:

    • Vary the inputs for each test
    • Write a test-case that ensures that your program works properly, and then write a corresponding test-case that ensures your program doesn't work the way it shouldn't

    Here's an example:

    TEST(MyTest, TwoPlusTwoIsFour) {
        ASSERT_EQ(4, 2+2);
    }
    
    TEST(MyTest, TwoPlusThreeIsntFour) {
        ASSERT_NE(4, 2+3);
    }
    

    On top of that, if you're unit-testing the logic inside your code (not the 3rd party libraries), then it's perfectly fine that you don't worry about the other code breaking, while in that context. You're essentially testing the way your logic wraps and uses the 3rd party utilities, which is a classic testing scenario.

Once you're done testing at the class level, you can go on to testing the integration between your classes (the mediators, from what I understand) and the 3rd party libraries. These tests are called integration tests, and do not use mocks, but rather the concrete implementations of all classes. They're a bit slower, but still very important!

share|improve this answer
add comment

Your Answer

 
discard

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