Organizing Test Data
One of the most annoying things I faced in the past was maintaining test data. Typically what I would do was write my test data in the test itself and then copy it for the next test, modify it where needed and so on. This resulted in lots of duplicated test data and meant that a small change could have a big impact as it needed to be changed in all the tests. To avoid this I have experimented with a couple of alternatives which helped me to clean up my tests and make the data more manageable.
There were 2 main groups of issues that I faced:
JSON data sent to my controllers or received from them was in plain text. I don't want to change this because relying on the same dto in your test undermines its purpose.
Creating objects is very cumbersome and had to be done over and over again.
A first attempt was to extract as much as possible to methods in the test class. This works up to a certain level as each test is likely to have some small change from the other, there isn't that much data that remains the same over all your tests. Nevertheless, this can help with created some data you require in your tests. For instance, the data returned by a mocked service and the corresponding JSON can be kept the same if you only want to test the behavior for a different request.
I then moved on to some data builders, such that instead of having a to statically create the JSON, I could create a JSON based on some data. Doing this for a flat JSON is easy and can be done with a single map. Having an object with nested objects is more troublesome. To solve that I started to create test versions of all of my objects. So next to a dto and dao, I also would have a test object. This test object would have methods to create the dto, dao and JSON objects. This groups all the logic on how to create the objects and data in a single place, it still means that in each test you have to create the test object in order to create the correct data you need.
Finally, I started to experiment with Object mothers. Even though I heard of them before, I never saw much benefit in using them. They do however seem to solve most of my problems. They actually are just a next step in my abstraction process. Object mothers don't just define a test object which can create the other required objects, but it provides canned examples that you can use. So instead of having to create the object in each test, you can use the object as is. Another advantage is that you can use the same test object across multiple test classes. For instance, you can use the same test object in your controller test, service test and even repository test. Some objects (such as user) can even be used across all of your tests as they are a core part of the application and used nearly everywhere.
Coming back to the two big challenges I had before, it is clear that object mothers solve both of them. It encapsulates the JSON creation in dedicated methods and creates the JSON based on the data that is part of the test object itself. Object creation is done by some factory method of the object mother itself and does not need to be in the test methods itself anymore. What still can be required is some minor tweaking of the test object. This should however be done with care, as it may be more valuable to create a new test object instead that can be used in other tests as well.