views:

271

answers:

5

You have a method on a class that has 2 parameters, one of which is a file path, the other is irrelevant.

InterestingResult result = foo.Bar(irrelevant, filePathInfo);

In the spirit of having fast snappy unit tests, you find yourself considering refactoring this method to pull out the file path to remove the IO requirements of this test...most likely putting it into another method, so that now you would call

string dataInFile = foo.GetDataInFile(filePathInfo);
InterestingResult result = foo.Bar(irrelevant, dataInFile);

Are you crazy?...or was this a good thing?

+6  A: 

How about using a Stream as argument instead? That way you can pass a MemoryStream in your unit test, and a FileStream in production code.

driAn
Stream is the way to go. Path interfaces can be infuriating. If your require seeking check stream.CanSeek and throw as appropriate.
plinth
A: 

As a general rule I would avoid changing an interface only for testing purposes. The interfaces should reflect the user's needs, not the developer's or the tester's.

mouviciel
"As a general rule I would avoid changing an interface only for testing purposes."... Right, you should design it for testing in the first place.
Robert Gowland
@slowplay: AMEN! Consider Test-Driven Development (TDD)--if it is not easy to test, then it won't be easy to use.
Rob Williams
That's right rob, because "testing a class" is "using a class" :-)
tjjjohnson
A: 

Depends who you ask. Some would say design for testing. I would not change my design merely to accommodate a test.

But in this case, I would change my design such that the Foo method takes a Stream rather than a file path. That way it is more flexible and your unit tests can just pass in a dummy stream.

HTH, Kent

Kent Boogaart
A: 

I would probably have the interface designed so that instead of taking a file path, I would pass in an IStream (or similar) pointer. That way you can use a Mock library for testing to pass in a mocked IStream that will satisfy the method, and provide a stronger test.

Nick
A: 

Simplest thing that works.

  • For your test, supply a (read-only) golden file for which you know the expected output.(store it in Test/Resources). If that is fast enough, no need to change production code.
  • If the test hitting the FileSystem is unbearably slow (anything over half a sec), Abstract out FileSystem Access (use a Mock/Fake) (something similar to the second snippet in your question).

As you get more n more test infected, you develop a sort of spider-sense of things that would be diff to test and design accordingly. So keep at it...

Gishu