Refactoring strategy for a class that generates a specific text file
I am a TDD noob and I have no idea how to solve the following problem. I have a fairly large class that generates a text file in a specific format for import to an external system. I am going to refactor this class and I want to write unit tests sooner.
What should these tests look like? In fact, the main goal is not to break the file structure. But that doesn't mean that I have to compare the contents of the file before and after?
source to share
I think you would benefit from a test that I would be embarrassed to call "unit test" - although it may be testing the current "block" creating a text file. This simply runs the current code and makes the difference between its output and the "golden master file" (which you can create by executing once and copying it to the specified location). If there is a lot of conditional behavior in your code, you can run it with multiple examples, each of which is a different test case. With existing code, by definition, all tests must pass.
Now start refactoring. Extract a method - or better, write a test for a method you can imagine, extract, a true unit test - extract a method and make sure all tests, for the new small method and for the larger system, still pass. Wet, rinse, repeat. System tests give you a safety net that lets you confidently move forward with refactoring; unit tests drive the design of new code.
Libraries are available to facilitate this kind of testing (although it's pretty easy even without them). See http://approvaltests.sourceforge.net/ .
source to share
In this case, I use the following strategy:
-
Write a test for each method (just cover its default behavior with no error handling, etc.)
-
Run the Code Coverage Tool and find the blocks not covered by the tests. Write tests that cover these blocks.
-
Do this until you have more than 80% code coverage.
-
Start refactoring the class (basically generate smaller classes after decoupling the worry principle).
-
Use Test Driven Development to write new classes.
source to share
In fact, this is a very good place to start (comparing the well-known result with the one generated by the current class). If one generator class can produce different results, then create one for each case. This will ensure that you are not breaking your current generator class.
One thing that can help you is to have a specification document for the current class. You can use this as the basis of your refactoring efforts.
source to share
If you haven't already, grab a copy of Michael Perce's book, “Work Effectively with Legacy Code . ” It's all about how to add tests to existing code you're looking for.
But until you finish reading this book, I suggest starting with a regression test: create a class, write a file to disk, and then compare that file to the "known good" file you hid in your original repository. If they don't match, skip the test.
Then start looking at the interesting decisions your class is making. See how you can check them out. Maybe you're extracting some complex if-conditions into public functions that return bool, and you're writing a battery of tests to prove that given the correct inputs, this function returns the correct value. Perhaps generating a specific string has interesting logic; start testing.
Along the way, you can find objects that want to exit. For example, you might find that the code (or tests!) Would be easier if there was a separate class that generates a single line of output. Deal with it. You've got your regression test to catch you if you come up with anything.
Work tirelessly to remove dependencies (but make sure you have a higher level test, like a regression test, to catch you if you make mistakes). If your class creates its own FileStream and writes to the filesystem, change it to use the TextWriter instead in its constructor so that you can write tests that are passed to the StringWriter and never touch the filesystem. After that, you can get rid of the old test that writes the file to disk (but only if you didn't break it when trying to write a new test!) If your class needs a database connection, refactoring until you can write a test that passes in fake data. Etc.
source to share