Accepting TDD for an Old Java Application

I have a problem and I ask you for help

I started working on a web application that has no tests, based on spring 2.5 and hibernate 3.2, not very modular, with classes having up to 5k lines, because JSP viewing technology uses everything over a place with quite a lot of duplicated ones (like many similar search forms with very few differences, but with few shared parts).

Application works well, but everything works fine, but when you need to add or change some functions, it is very slow and not very convenient.

Is it possible to use TDD at the moment? Or what would you advise, because I do not think that I can develop it forever, as it is now, it always becomes messy.

Thank you for your answers.

+4
source share
6 answers

I would start by taking a copy of Michael Persa’s book, Working Effectively with Outdated Code, is pure gold.

Once you learn refactoring methods and break your application at its logical seams, you can work on integrating TDD into new classes and methods for modules / seedlings, etc.

The fact is that we recently switched to the TDD approach for a ten-year application written in almost all versions of our frameworks, and while we are still struggling with some parts, we made sure that all our new work is abstracted and all new code is under control .

It’s absolutely doable - it’s just a little more complicated, and the book above can be a huge help when starting work.

+4
source

Firstly, welcome to the club of poor good programmers who must fix the crimes committed by their worst colleagues. :(

I had such an experience. In this case, one of the recommended practices is to develop tests for new features. You cannot stop now and develop tests for the entire application. What you can do is every time you have to write new tests to develop this function. If this feature requires changes in some sensitive locations, start testing for those locations.

Refactoring is a big problem. Ideally, if you want to divide a 5k row class into 10 normal-sized classes, you should first develop a test case for a large class, then do the reprocessing and then run the tests again to verify that you didn't break anything. This is very difficult in practice, because when you change the design, you change the interface, and therefore you cannot perform exactly the same tests. So, every time you have to make a difficult decision, which is the best way and what is the minimum test case that covers your ass.

For example, sometimes I performed a phase factorium: 1. developed tests for a poor large class 2. developed a new well-designed code and changed the old class to the facade of my new code. 3. checked the test case developed in No. 1 to confirm that everything works 4. developed new tests that confirm that each new (small) auxiliary module works well 5. reorganized code, i.e. Removed all references to a large old class (which became a light facade) 5. deleted the old class and its tests.

But this is the worst case scenario. I should have used it when the code I am changing is extremely sensitive.

Good luck with your hard work soon. Get ready to work overnight, and then get 20 bug reports from QA and an angry email from your boss. :( Be strong. You're on the right track!

+3
source

If you feel that you cannot make any changes for fear of breaking things, you answered your question: you need to do something.

First hole rule: If you get stuck in a hole, stop digging.

You need to introduce such a policy that if the code is passed without a test, this is an exception, not a rule. Use continuous integration and get people to keep going.

I recommend starting with capturing the main functionality of the application in tests, both per unit and integration. These tests should be basic, which show that the required functionality is working.

You mentioned that there is a lot of code duplication. This is the next place. Test around the area with duplicate code. You will be testing 2 or more points here since duplication exists. Then refactor and see if the tests pass.

As soon as you knock one domino down, the rest will follow it.

+2
source

Yes, of course, there is room for TDD, but this is only part of the solution.

You need to refactor this application before you can make any changes. Refactoring requires coverage for testing. Take small portions of clearly non-standard code and write characterisation tags for them. This means that you are checking all possible variations of this code. You will probably find errors. Raise errors through your quality control system and continue to work with the error (block errors with your performance tests, as other parts of the system may currently rely on error behavior).

If you have very long and complex methods, you can encourage your IDE to extract small portions to separate methods when necessary. Then write performance tests for these methods. Attack large methods this way, in different ways, until they are well separated. Finally, after you have the tests, you can reorganize.

Tests

integration can be useful in this case to highlight happy day scripts or some serious error scenarios. But usually in this case the application is too complex to write a full set of integration tests. This means that you can never protect 100% from side effects using only integration tests. That is why I prefer the “extraction method" and characterize it.

Now that your application is protected from side effects, you can add new features using TDD.

+1
source

My approach would be to start adding tests in parts. If there is a section that, as you know, you will need to update in the near future, start getting good coverage in this section. Then, when you need to update / refactor, you have your regression tests. According to him, this will be a serious obligation to create a comprehensive set of tests, but most likely it will most likely pay off. I also suggest using one of the available code coverage tools to see how much your tests really cover.

Hooray!

0
source

At the moment, you probably can’t create test development, unless you add functionality that is easy to isolate from the rest of the system (which is unlikely).

However, you can (and should) be sure to add automated tests of your core functionality. At first, this will not be real unit tests in the sense of testing small units of code in isolation, but IMO is often overstated for them. Integration tests may not work as fast or help you pinpoint the cause of errors, but they still help a lot to protect you from the side effects of changes. And this is what you really need when you refactor your code to make future changes easier and more realistic unit tests.

In general, go for low hanging, but juicy fruit first : write tests for parts of the code that can be easily tested or break easily, or cause most problems when they break (and where the tests are thus most valuable), or , ideally, all of this together. It gives you real value quickly and helps convince reluctant developers (or managers) that this is a path worth pursuing.

A continuous build server is a must. The set of tests that people must remember to run manually in order to benefit, means that you spend most of your benefits.

0
source

All Articles