Java – how and should I ‘unit test’ an entire package

javamockingtestingunit testing

I'm still learning to be good about doing unit level testing, as I've always been a little sloppy about only doing functional testing in the past, so I want to double check I'm doing this 'right'.

I have a package which is responsible for auto-magically updating a particular configuration which is expected to change regularly during runtime. Provide a list of objects to monitor to the constructor of my main package class. Then at some point call update it will go to all the multiple places that define configuration, detect change, update the appropriate state for the objects it's monitoring, and provide a report of what was changed. This is all automatic and otherwise transparent to all other packages.

My inclination is to test this as a unit, but it is a pretty 'big' unit, 5-6 classes and fetching from multiple files and a restful interface. It feels like testing any smaller units would take much longer, be less flexible to refactoring and only provide a slightly higher chance of detecting a defect, but that could just be my laziness talking. Would it be considered 'better' to test at a lower level?

Assuming it is 'right' to test the package as a unit what is considered appropriate for mocking something like this? There are methods of classes which are instantiated by my main class (ie, not something I pass in directly so I can't just pass my own mock) that have methods I want to control. I believe I can use powerMock in the two cases I can think of (or could, after I research PowerMock some more), but I'm not sure if doing so is transparent enough. Is configuring PowerMock to detect and return a mock file object any time my package tries to open a configuration file, even if it's buried deep in my package logic, acceptable, or is this considered to be abusing my knowledge of implementation specific details? Would it be 'cleaner' to actually modify configuration files on the file system and let them be read normally without further mocking? I would need to modify the files regularly for testing…

Edit:
To clarify the question of coupling asked in one of the questions, I don't think that my classes are overly coupled. Effectively I have three classes that fetch state from A, B, and C, and then a 'main' class which takes the state from the three and decides how to combine it correctly (ie, if A and B don't match use A unless C). I could easily test A B and C separately and then mock them to test my 'main' class. However, it seems like the testing of my 'main' class would effectively test the comparatively simple interfaces for A, B, and C anyways if I didn't mock them. Thus it feels like duplicate work to test them individually. I may get some slightly better code coverage, maybe, with individual testing, and it's always nice to have one test test only one thing. But I don't know if it's worth all the overhead for minor benefits.

Best Answer

Unit testing is the lowest level of testing, but that means only that it is the lowest level you do, not the lowest level you could theoretically do. If you test at the class level, you could test at the method level, using an appropriate test tool to get at private members. But if you test at the method level, you could test at the statement level, using an appropriate test tool to get the statement in isolation so you test it. And if you did decide to test at statement level, that's still a decision not to test at instruction or byte code level. And that process of decomposition only stops when someone decides 'a smaller unit would be stupid'.

So the question 'how should I unit test this' is exactly equivalent to 'how should I first test this'. If the best way of testing a package is as a whole, because it is of a size and complexity where testing it as a unit is the most effective way of meeting your reliability and maintainability goals, then do so.

If it isn't, then don't.

Anyone trying to give more specific advice without either seeing your code base or knowing your project context (nuclear power plant in basement of an orphanage, or email spam generator?) is very likely not merely wrong, but also unwise.