Is it good or bad to duplicate data between tests and real code? For example, suppose I have a Python class
FooSaver that saves files with particular names to a given directory:
class FooSaver(object): def __init__(self, out_dir): self.out_dir = out_dir def _save_foo_named(self, type_, name): to_save = None if type_ == FOOTYPE_A: to_save = make_footype_a() elif type == FOOTYPE_B: to_save = make_footype_b() # etc, repeated with open(self.out_dir + name, "w") as f: f.write(str(to_save)) def save_type_a(self): self._save_foo_named(a, "a.foo_file") def save_type_b(self): self._save_foo_named(b, "b.foo_file")
Now in my test I'd like to ensure that all of these files were created, so I want to say something like this:
foo = FooSaver("/tmp/special_name") foo.save_type_a() foo.save_type_b() self.assertTrue(os.path.isfile("/tmp/special_name/a.foo_file")) self.assertTrue(os.path.isfile("/tmp/special_name/b.foo_file"))
Although this duplicates the filenames in two places, I think it's good: it forces me to write down exactly what I expect to come out the other end, it adds a layer of protection against typos, and generally makes me feel confident that things are working exactly as I expect. I know that if I change
type_a.foo_file in the future I'm going to have to do some search-and-replace in my tests, but I don't think that's too big of a deal. I'd rather have some false positives if I forget to update the test in exchange for making sure that my understanding of the code and the tests are in sync.
A coworker thinks this duplication is bad, and recommended that I refactor both sides to something like this:
class FooSaver(object): A_FILENAME = "a.foo_file" B_FILENAME = "b.foo_file" # as before... def save_type_a(self): self._save_foo_named(a, self.A_FILENAME) def save_type_b(self): self._save_foo_named(b, self.B_FILENAME)
and in the test:
self.assertTrue(os.path.isfile("/tmp/special_name/" + FooSaver.A_FILENAME)) self.assertTrue(os.path.isfile("/tmp/special_name/" + FooSaver.B_FILENAME))
I don't like this because it doesn't make me confident that the code is doing what I expected --- I've just duplicated the
out_dir + name step on both the production side and the test side. It won't uncover an error in my understanding of how
+ works on strings, and it won't catch typos.
On the other hand, it's clearly less brittle than writing out those strings twice, and it seems a little wrong to me to duplicate data across two files like that.
Is there a clear precedent here? Is it okay to duplicate constants across tests and production code, or is it too brittle?