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.

My current job is mostly writing GUI test code for various applications that we work on. However, I find that I tend to copy and paste a lot of code within tests. The reason for this is that the areas I'm testing tend to be similar enough to need repetition but not quite similar enough to encapsulate code into methods or objects. I find that when I try to use classes or methods more extensively, tests become more cumbersome to maintain and sometimes outright difficult to write in the first place.

Instead, I usually copy a big chunk of test code from one section and paste it to another, and make any minor changes I need. I don't use more structured ways of coding, such as using more OO-principles or functions.

Do other coders feel this way when writing test code? Obviously I want to follow DRY and YAGNI principles, but I find that test code (automated test code for GUI testing anyway) can make these principles tough to follow. Or do I just need more coding practice and a better overall system of doing things?

EDIT: The tool I'm using is SilkTest, which is in a proprietary language called 4Test. As well, these tests are mostly for Windows desktop applications, but I also have tested web apps using this setup as well.

share|improve this question
    
What test tool are you using? It may be that your testing framework isn't supporting the types of tests you are writing. Cut-n-paste of more than 3 lines is generally really bad, but if you are able to clearly add more long-term value by automating a GUI test than by performing it manually every time, then whatever you are doing is probably pretty darned good. –  GlenPeterson Sep 19 '12 at 19:02
    
Also, what language is this? You may have something available that's just not popping into mind, that would allow reuse (like first class functions). On the other hand, test cases are supposed to be kept simple, to keep it less likely they have bugs themselves... –  Izkata Sep 19 '12 at 20:59
3  
In anything I've written, testing code isn't excluded from refactoring.. –  Simon Whitehead Sep 19 '12 at 22:52
add comment

8 Answers

up vote 16 down vote accepted

Copy-pasted and then edited test cases are often fine.

Tests should have as few external dependencies as possible, and be as straightforward as possible. Test cases tend to change with time, and previously almost identical test cases may suddenly diverge. Updating one test case without having to worry about breaking other cases is a Good Thing.

Of course, boilerplate code which is identical in many test cases and has to change in concert can and should be factored out.

share|improve this answer
    
This is mainly how I feel. Nearly identical test code is ok in a lot of cases, but identical test code repeated is bad news. –  joshin4colours Sep 20 '12 at 21:39
add comment

Repetition is the root of all evil

That is right! Repetition is the root of all evil. Probably it was Knuth saying in his book “Premature optimization is the root of all evil”, but I think it’s repetition.

Whenever you look at a program or you’re writing one and you discover some kind of repetition: Remove it! Kill it immediately… whatever but get rid of it!

Each time I introduced some sort of repetition and had to fix a bug in there, I forgot to fix the replica...(Donald Knuth) So, whenever there is a repetition just remove it as best as you can, don’t hack!

Think of a clean lean design (like, encapsulating your repeating code blocks in helper classes) and write some tests before changing something (just to be sure you didn’t break something). This is true for any piece of code that is written and test codes are no exception.

Here is a good reading from Code Horror that inspires me - A Modest Proposal for the Copy and Paste School of Code Reuse.

share|improve this answer
    
"Each time I introduced some sort of repetition and had to fix a bug in there, I forgot to fix the replica…" exactly. Also, if you c&p and you forget to adjust the copied text to your current context this will hurt a lot. Bugged test code doesn't sound like the optimal situation, now does it? –  mcwise Sep 19 '12 at 18:09
    
yeap, i took the stations from Knuth :) –  Yusubov Sep 19 '12 at 18:14
6  
You repeated yourself: You repeated yourself by saying "Repetition is the root of all evil" in the title and your intro sentence. –  Thomas Eding Sep 19 '12 at 19:08
    
Yeap, i did that intentionally to stress the importance and you are welcome to edit thats part :) –  Yusubov Sep 19 '12 at 19:18
1  
Thomas Eding, you repeated yourself as well. You repeated yourself as well =) –  mcwise Sep 20 '12 at 7:13
show 1 more comment

It's still pretty bad to cut and paste. There are a few problems.

Your tests may well be brittle, because you are vulnerable to something that requires a change in all that copy-and-pasted code. Will you have to rewrite all the tests?

If you can't encapsulate the logic into helper methods outside your tests, you can't write tests of those helper methods themselves. Writing tests of test methods is usually to hard to make worthwhile, since you have to break your code to test the test. But you can unit test helper methods.

It may well make the tests less readable. A big block of copied code may be harder to read than a call to helper method with a descriptive name.

Everything I've listed is something that may be a problem. If you find none of them actually are a problem then of course it's fine.

share|improve this answer
add comment

I used to agree with you. But then, over time, I found that every change I made (particularly DI changes in unit tests) required numerous tests to change and that was cumbersome. Now I subscribe to the school of DRY, even when writing tests.

For GUI testing, you may want to look at the PageObject pattern to reduce repeated code.

share|improve this answer
add comment

I would recommend picking up XUnit patterns. I used to have the exact same problem until I started leveraging that book. The Object Mother pattern sounds like it would be the most helpful for your scenario.

Like someone else mentioned, properly encapsulating this setup code might be onerous, but having to change it in all the places you copy and pasted is even more so.

share|improve this answer
    
+1 for the Object Mother pattern for common initialisation code. –  k3b Sep 19 '12 at 19:21
add comment

Should people try and limit repitition when they can - yes. But the payoff depends on the situation. This could go back to the 'best practice' debate. But the question is what is best for you in this situation. There are exceptions to every rule.

A couple things I would ask are: 1) How likely is it that this functionality being tested in the UAT will change? If it is unlikely it will change, then there is less chance that you will have to update each of your sets of code. 2) If there is a change in UAT, will it always impact each set of the copied code or might it only impact one or two sets? If it might be isolated and only require a change to one set, it might help to have the things separated. 3) How complex will the initial method be if you try and have it handle all scenarios? Are you adding a lot of nested if/else/loops? If you start over-doing all the branching, you may end up with code that is hard to comprehend. Would it be easier to make the update in each of the copied text than it would be to revisit all the branching logic?

If you are stuck copy/paste/alter I would think you would want to add comments such as 'This is copied in method xyz'. That way you will be reminded to update all the pasted versions of the code. Or (coming from another SilkTest user) could you add a separate inc file that would focus just on this repeated code. That way you have all the variations in one place and could easily see the different methods that would require updating.

share|improve this answer
add comment

One Big Procedure

One thought: It sounds like you are trying to avoid cut-n-paste code by making methods like:

testScreen(title, fieldList, linkList, param1, param2, param3,...) {
    test that the layout at the top of the screen is correct
    test if PageTitle == title?
    for each field in fieldList:
        check that it appears in order on the screen
    for each field in linkList:
        check that it appears in order on the screen
    test if param1 is whatever...
    test if param2 is whatever...
    etc.
    test that the bottom of the screen is correct
}

Many Little Procedures (toolkit)

Have you also considered the opposite approach? Instead of passing a million parameters to one big testScreen() procedure, maybe make your own framework or tool-kit of little helper procedures that you whip out as you need them. Like:

testScreenTop()
verifyLinks(list)
testScreenBottom()

You still cut and paste these procedures into every screen, but you are cutting and pasting smaller chunks of code and carving out chunks of commonality that are not cut and pasted (the contents of each little procedures).

Cut and Paste

The only time cut-and-pasted code hasn't bitten me was when the code was thrown away before I had to change it. My biggest concern with UI tests is how quickly they become obsolete. If you find you throw all your code away before you change it, then maybe you have found a niche where cutting and pasting is OK! Also, it's not so bad when there is no code downstream from the cut-and-pasted code (e.g. in the UI of an application). If you are pasting more than 3 lines, I'd really look into doing something about it. At least take steps to minimize it!

Automated UI Testing

Heck, if you can prove greater productivity with automated UI testing than manual testing using any technique (the cost of writing/maintaining automated tests is lower than testing manually every time, yet quality is the same) I think you should write a paper. I would read it! I can see the title now, "Cut-and-paste Code a Net Win for UI Testing!"

share|improve this answer
add comment

It's really not that bad. In fact, if you find certain code patterns are being used very often and the changes are very routine (such as a few strings, or parameter values), you could even write a code generator that generates repetitive test code based on a small(-ish?) input list of values that change. I've done this (generated test code) many times, using batch files, SQLPlus scripts, even Excel macros (it sounds ugly, but the variables for the different test scripts were already in a spreadsheet) and it can be a great time saver. The thing is that if anything changes in the overall structure of the repetitive test case code, you can just regenerate whatever you need.

share|improve this answer
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.