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 have a recurring question when writing unit tests for code that involves constant string values.

Let's take an example of a method/function that does some processing and returns a string containing a pre-defined constant. In python, that would be something like:

STRING_TEMPLATE = "/some/constant/string/with/%s/that/needs/interpolation/"

def process(some_param):
    # We do some meaningful work that gives us a value
    result = _some_meaningful_action()
    return STRING_TEMPLATE % result

If I want to unit test process, one of my tests will check the return value. This is where I wonder what the best solution is.

In my unit test, I can:

  1. apply DRY and use the already defined constant
  2. repeat myself and rewrite the entire string
def test_foo_should_return_correct_url():
    string_result = process()

    # Applying DRY and using the already defined constant
    assert STRING_TEMPLATE % "1234" == string_result

    # Repeating myself, repeating myself
    assert "/some/constant/string/with/1234/that/needs/interpolation/" == url

The advantage I see in the former is that my test will break if I put the wrong string value in my constant. The inconvenient is that I may be rewriting the same string over and over again across different unit tests.

share|improve this question
add comment

4 Answers

up vote 8 down vote accepted

There's a little warning about the DRY principle that many people aren't aware of: Don't get so obsessed about avoiding repetition that you remove 'duplicates' of things that appear to be the same but are actually conceptually very different.

As an extreme example you wouldn't try to remove the repetition of the duplicates of '/s', 'th', 'on', 'nt', etc within your original string.

In your particular example, you don't/shouldn't care about implementation details of your code under test. (I.e. that it uses the STRING_TEMPLATE const.) Your test cares about the fact that when you:

void Test() {
  DoSetup(...);
  ActualResult = DoProcess(...);
  Check(ActualResult == "/some/constant/string/with/1234/that/needs/interpolation/");
}

The fact that "/some/constant/string/with/1234/that/needs/interpolation/" is similar to STRING_TEMPLATE should be considered coincidental, not a violation of DRY.

NOTE: This of course doesn't apply if you're actually testing some localisation aspect of your system, or if your system is affected by localisation that you initially set up via STRING_TEMPLATE. Because then the duplication is explicit.

share|improve this answer
    
I like your answer. I agree that the fact that we use a constant is an implementation detail and if you treat it as such, you should ignore it in your unit test. However, given that you are 'omniscient' about the code when you write unit tests, sometimes it's not obvious to see what is only an implementation detail and what matters. –  Rodrigue Jul 2 '12 at 6:54
add comment

First off in your example, you are actually testing two things in a single unit test, a unit test should only test one thing at a time.

What you should be testing:

  1. the constant value is in the format or a proper URL with a single % wildcard position.
  2. the string replacement inside the build_url function actually produces a valid URL given a valid input to the function

in addition you should test

  1. the constant fails to validate the constant value if it is not a valid URL pattern with a % position ( and all the mutations of this )
  2. the string replacement inside function fails to create valid URLs with invalid input

These should be two separate unit tests.

share|improve this answer
    
I like the idea of testing the constant separately. That is what I often do: I write a test that interpolates my template and makes sure I get the expected output. After that, I use the constant in my other unit tests. –  Rodrigue Jul 1 '12 at 17:42
add comment

I usually prefer to manually specify the expected result. While it's unlikely that the string interpolation in your example will break, there might be a case where you use a third party library to build the result. Using manual results will uncover version incompatibilities in these libraries. Also, there's always the danger of strange environmental circumstances that might break the function, like locale, encoding, 32- / 64-bit platforms, or similar. Sometimes, those actually break the function. Other times, they just broke the unit tests with their manually typed results. In either case, it's worthwhile to check.

If you test functions without side effects, you could use data-driven testing, which allows you to keep test inputs and expected outputs close together.

However, in your particular example, it might be a good idea to not hard-code the URL_TEMPLATE, but read it from some configuration file. This will ease the transition between different environments.

share|improve this answer
    
Thanks for the answer. I think I made my example too simple though. I don't really want to make sure the interpolation works. I am more thinking of a case where foo would do more things and as part of generating its output, use a constant I have defined. I would then need to check that somewhere, the returned value contains the right string. I will figure a better example. –  Rodrigue Jul 1 '12 at 17:34
add comment

This is a good candidate for "Things that shouldn't be unit tested."

What business logic are you testing?

That the constant is set correctly? The test is just repeating the code then (which is a sign you shouldn't be testing it).

That the language is doing string replacement properly? It's not your job to test the language.

share|improve this answer
    
My example is simple to stupidity which probably doesn't help my point. I'm thinking of the case where my foo would do other things and at some stage use the string constant to produce it's output. How would I check that the output contains the value of the constant? –  Rodrigue Jul 1 '12 at 16:42
    
@rodrigue: what's the requirement? if the requirement refers to the constant (regardless of value) then test versus it. If the requirement refers to the value of the constant (and the constant is an implementation detail) then test the value. –  Telastyn Jul 1 '12 at 16:44
    
Downvote for "candidate for things that shouldn't be tested" - since the question isn't about the example –  Murph Jul 1 '12 at 18:30
    
@murph: regardless, the constant string isn't part of what you should be testing. –  Telastyn Jul 1 '12 at 18:48
add comment

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.