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.

Main excuse from the developer for not having a good unit testing is "Code is not designed in a unit testable fashion." I am trying to understand what type of design and code that can't be unit tested.

share|improve this question
2  
Your excuse? A co-workers? Managers? What language / frameworks are you working with? –  MichaelT Dec 26 '13 at 20:59
1  
A lot of legacy code in the application and no time for redesign. –  knut Dec 26 '13 at 21:10
4  
@gnat: I disagree. The question you quoted is about situations in which unit tests are not useful. The current question is about situations which render unit tests difficult. –  MainMa Dec 26 '13 at 21:16
    
@MainMa apparently we read different questions. "I am trying to understand what type of design and code that can't be unit tested." => "When is it appropriate to not unit test?" –  gnat Dec 26 '13 at 21:17
1  
@manizzzz: you might want to edit that into the question. –  jmoreno Dec 29 '13 at 20:19
show 7 more comments

6 Answers

Several factors may render the code difficult to unit test. When this is the case, refactoring helps in improving the code in order for it to be testable.

Some examples of code which would probably be difficult to test:

  • A 1000-LOC function,
  • Code which heavily relies on global state,
  • Code which requires concrete, complicate to build objects, such as database context, instead of relying on interfaces and Dependency Injection,
  • Code which performs slowly,
  • Spaghetti code,
  • Legacy code which was modified for years with no care about readability or maintainability,
  • Difficult to understand code which has no comments or hints about the original intention of the author (for example code which uses variable names such as function pGetDp_U(int i, int i2, string sText).

Note that the lack of clear architecture doesn't render code difficult to unit test, since unit tests concern small parts of the code. Unclear architecture would still have a negative impact on integration and system testing.

share|improve this answer
8  
Also it's hard to test code that does not inject dependencies on non-pure functions, like random numbers, current time, hard-wired I/O, etc. –  9000 Dec 26 '13 at 21:16
    
its trivial to test code like that - you just need the right test tooling, not to mangle your code to suit them. Try Microsoft Fakes for an example. –  gbjbaanb Dec 31 '13 at 19:58
    
@MainMa, I like this answer. Would you also be willing to comment a bit on what factors push different tests to integration and system testing? I know that the reason I've asked similar questions to the one here in the past is that I didn't have a roadmap explaining what types of tests are best put where (or perhaps, most cost-effectively put where) - I thought unit tests were the one-and-only. –  J Trana Jan 1 at 5:13
add comment

There are a lot of things that make code difficult to unit test. Coincidentally a lot of those also happen to make code difficult to maintain:

  • Law of Demeter violations.
  • Creating objects inside a method instead of injecting dependencies.
  • Tight coupling.
  • Poor cohesion.
  • Relies heavily on side effects.
  • Relies heavily on globals or singletons.
  • Does not expose much intermediate results. (I once had to unit test a ten page long math function with a single output and no available intermediate results. My predecessors basically hard-coded whatever answer the code happened to give).
  • Depends heavily and directly on services which are difficult to mock, like databases.
  • Runtime environment is significantly different from development environment, like an embedded target.
  • Units only available in compiled form (like a third-party DLL).
share|improve this answer
    
I think this is an excellent answer. You touch on many code level issues, and global state issues. @MainMa has some other issues that I think are valid, but less well defined. Jeffery Thomas mentions I/O and UI. I think if you add the good parts of these three answers you'd have a great cohesive response. I like this answer best though because of the focus on code antipatterns. –  M2tM Dec 26 '13 at 23:01
    
Argh - nothing worse than unit test asserts that have no resemblance to business requirements and are just the output at a given time - mocks that are setup to be called 3 times for example? Why 3? Because it was 3 the first time the test was run /rant :) –  Michael Dec 30 '13 at 9:12
    
Tight coupling is only bad when it's inappropriate. Tight coupling in code that it's highly cohesive is a necessity. For example a variable declaration followed by its use. Tightly coupled, highly cohesive. –  dietbuddha Jan 4 at 20:15
add comment

Common examples of code people don't wish to unit test:

  • Code which directly interacts with i/o (reading files, direct network calls, …).
  • Code which directly update the UI.
  • Code which directly references singletons or global objects.
  • Code which implicitly change the object or sub-object state.

Using a mock framework, all of these examples can be unit tested. It's just work to setup the mock replacements for the internal dependencies.

Things which truly can't be unit tested:

  • Infinite loops (for a thread manager, driver, or some other type of long running code)
  • Certain types of direct assembly operations (which some languages support)
  • Code which requires privileged access (not impossible, just not a good idea)
share|improve this answer
add comment

The are a few areas that can make it more difficult to write unit tests for. However, I would stress that that doesn't mean you should discount useful techniques out of hand simply because they may add some complexity to your testing. As with any coding you should be doing your own analysis to determine if the benefits outway the costs, and not blindly accept what some random guy posts on the net.

Poorly written of designed code

  • inappropriate coupling (usually tight coupling where it shouldn't be)
  • kitchen sink code (where a function has far too much logic/responsibilities)

Reliance of state in a different scope

The cost for most of these spiral out of control unless you know what your doing. Unfortunately, many often don't know how to use these techniques in ways to mitigate things like testing complexity.

  • Singletons
  • Globals
  • Closures

External/System State

  • Hardware/device dependencies
  • Network dependencies
  • Filesystem dependencies
  • Inter-process dependencies
  • Other system call dependencies

Concurrency

  • Threading (locks, critical sections, etc)
  • fork'ing
  • Coroutines
  • Call Backs
  • Signal Handlers (not all, but some)
share|improve this answer
add comment

There's no such thing as code that can't be tested. There are, however, a few examples of code that's REALLY, REALLY hard to test (to the point of possibly not being worth the effort):

Hardware interactions - If the code directly manipulates the hardware (for instance, writing to a register to move a physical device), then unit testing it might be too difficult or expensive. If you use real hardware for the test, that can get pricey to get appropriate feedback into the test harness (yet more equipment!), and if you don't, you have to emulate the exact behavior of physical objects - no small trick in some instances.

Clock interactions - This is usually easier, because it's almost always possible to mock out the system clock functions pretty trivially. But when you can't, then these tests become unmanageable - tests that are based on real-time tend to take a long time to run, and in my experience they tend to be very brittle as system loads make things take longer than they should, causing phantom test failures.

share|improve this answer
add comment

My main three groups for this are:

  • code that relies on external services

  • systems that don't allow testers to modify state independently of the application.

  • test environments that don't replicate the production setup.

This is what I've experienced the most as a developer turned QA engineer.

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.