I currently have an interesting situation occurring with my code, and after hacking away at what turned out to be a dead end for the last two weeks, I’m here asking those smarter than I to educate me on where I went wrong, and how I can perform my intended task correctly.
The setup:
We have a set of classes that perform various tasks but do so on one object that they pass around. Actions are performed to this object in each class before finally being processed and then sent back to the display layer for front end processing. This is a brief description of how the process works.
A collection of users is submitted via front end form
The collection of users is processed into an object with various parameters set within.
Multiple classes with various methods that process the object that was just created are executed one at a time. In each class, the object has various methods that perform tasks on certain actions, such as formulas, validation, etc.
the object is then sent to the front end for display of the processed object.
The task:
I’m attempting to build JUnit tests to help automate testing for this group of classes. This is how i have it configured
testConfiguration – instead of a form submission, I create a collection of users in various configurations based upon what we need to do for testing
testMain – This is the “root” class. It takes a configuration from the testConfiguration class needed for the current test run, creates it into an object with various parameters based upon the users passed, and then passed into the various classes for further processing
testClassesProcess – various classes that take the processed object from testMain, perform various actions on it (mainly mathematical type methods) and then return.
The issues:
Ran into a few really. The first is that you can’t pass parameters to functions in JUnit tests, as it’ll come up with initializeErrors. Also the @Autowired annotation in the classes being tested error out with NullPointerException
, turns out that if enter the classes being tested from the JUnit suite, and they can’t seem to resolve the variable that would be used with no issue when executed via the application normally.
WE currently use Java 1.7 with Hibernate, Spring, and JUnit to help give a visual of our stack.
So I’m wondering if after describing my situation if I’m trying to make JUnit put a round peg in square hole, if I’m just using JUnit wrong, or if there’s a better solution that I could use to test this setup.
EDIT: My apologies if this seems vague. It’s a workplace issue so I try not to give away anything proprietary, and to make it so others could relate.
I understand you are leaving some details out due to the proprietary nature of the project. This answer is my take on what is going on based on how I understand the question. Please leave a comment if I am off base here and I will edit accordingly.
I think you may misunderstand how to use JUnit in complex projects.
Each test needs to stand on its own: there is no reason to pass parameters into tests, because each test should be treated conceptually as a main
function. If you really need to do something before a test, you can annotate methods to run before/after each test or all tests (@Before
, @After
, @BeforeClass
, @AfterClass
). In practice, I have found such methods only useful for tests that connect to remote resources such as a database. While in general that is a bad idea, there are some specific cases where it makes sense. For example, when writing a driver where you really are testing the JDBC layer itself.
That brings me to the next point: in general, a unit test is for a specific piece of code, not the application as a whole or other components. To do this, you need to apply your SOLID principles to break software into smaller components that are loosely coupled to other components.
Once an object has one responsibility, you can more easily mock the components it relies on. Based on your breakdown of the various classes, you should consider using interfaces to define each component. That way you can have the “real” and mock classes both implement the interface and work correctly. This also has a benefit of helping ensure classes are only using the public interface (as opposed to package-private members) which further loosens coupling.
It sounds like you have a lot of interdependencies which make it difficult to “break off” a bite-sized chunk to test. I think you need to take a look at breaking up the design so you can inject your test mock objects which allow you to focus a single test on a single component which should not need additional information to run.