Graphs of serialized objects for organizing unit tests

I have an application where the problem domain is represented by domain objects that are highly interconnected. I split the domain into several aggregate root objects that help to put order in the model, but organizing the prerequisites for unit tests is difficult, because creating instances of these aggregate roots requires creating a large number of referenced supporting objects.

I want to write repeated isolated test tests that use the application without the need for external dependencies (and ideally without writing a huge piece of code).

I think these are my options. Any preferences or other suggestions?

  • Write build scripts that configure the project database and the INSERT of known data for which unit tests are performed. This is my least favorite option, as it introduces an external dependency (and therefore is not a unit test truth), as well as many other potential failures. It also does not isolate the business function being tested, since the error may be in the data access code.

  • Create reusable factories that create domain objects with a known state against which unit tests are run. This will work well, but it means that you need to write a lot of template code, and therefore they need to be changed when / if the model changes.

  • (Current method) Create binary serializations of my aggregated root objects to files verified by a test project. The unit tests their deserialization for their tests. The disadvantage of this is that if the base type changes deserialization, it will fail and all serial files must be recreated.

  • Connect it and write your own serializer that serializes the graphics into XML files that can be checked in the solution and deserialized during testing. Like 2, this means that you need to write the complete code for the template, but maintenance is easier because the serialized state can be easily edited using a text editor if the model changes.

  • UR DOIN IT RONG. The main problem is that your domain objects are so referential. Simplify this.

Thanks!

+4
source share
2 answers

Record build scripts that install the project database and INSERT into it against which unit tests are performed. This is my least favorite option, as it introduces an external dependency (and therefore is not a unit test truth), as well as many other potential failures. It also does not isolate the business function being tested, since the error may be in the data access code.

“Integration is not a unit” is a minor issue (especially compared to “test or not testing”), I would not worry about that. There are other, more serious problems with this approach:

  • Script writing. Most likely, you will end up coding SQL manually, which requires a lot of discipline, especially when the model is complex. Typos are painful, difficult to debug / detect problems, you also need to consider IDE / tools.
  • When your model changes, you will correct these SQL scripts, which leads to the same problems - typos, difficulty finding errors, etc. Lack of IDE support.

In general, this approach is expensive in terms of maintainability .

Create reusable factories that create domain objects with a known state against which unit tests are run. This will work well, but it means that you need to write a lot of template code, and therefore a lot changes if / if the model changes.

Decent approach, you should explore the libraries that facilitate this process (tooltip: AutoFixture , NBuilder ).

(Current method) Create binary serializations of my aggregated root objects to files verified by a test project. The unit tests their deserialization for their tests. The disadvantage of this is that if the base type changes deserialization, it will fail and all serial files must be recreated.

The same problem as build-scripts will be expensive.

Connect it and write your own serializer that serializes the graphics into XML files that can be checked in the solution and deserialized during testing. Like 2, this means that you need to write another code for the template, but maintenance is simpler because the serialized state can be easily edited using a text editor if the model changes.

This is essentially the same solution as your second, but with XML as the man in the middle. Why add an extra layer?

UR DOIN IT RONG. The main problem is that your domain objects are so referential. Simplify this.

Rather unlikely. In their domain nature objects, they tend to be complex.

Conclusion

There are no quick and dirty workarounds in this problem. A difficult area means that at some point there must be some extra work. Serialization-based solutions (1, 3, 4), even if some of them may seem easy, will delay additional work until changes are made. In almost every case, I would have the best flexibility and willingness to change (which offers only a second solution - if done correctly).

+3
source

The problem you are talking about is that the data is scattered in the field-object-graph:

if you want to calculate the price for an invoice, you need the price of goods, tax information, special data for specific customers, delivery of specific shipping-consts, ....

One strategy to combat this complexity is to split the logic into obtaining these detailed values ​​from the actual calculation.

Calculation is an internal method with many parameters and minimal dependence on other domain objects. This can be easily tested since it no longer depends on the graph of the object.

Another strategy is to move complex settlement from the domain to a separate service server, which depends on other service interfaces. For testing, these service interfaces can be replaced with mocks.

0
source

All Articles