Writing junit tests to deal with inheritance hell - java

I'm looking to add some junit to our code base.
We have a set of classes that inherited from an abstract base class. The inheritance is several layers deep (Base-> A, B, C ->C1, C2, C3->C3-1, etc). Sometimes someone overrides a method of a class (Class A) which has several child classes. But because of that, we get bad results for those in call children classes of Class A.
So, I'm looking for solutions to be able to try to prevent this and create a testing framework to deal with this.
My initial though is that we would need to create a TestSuite that would need to check that the TestClass has at least 1 test case for every method in the Base class via reflections. This would make sure the person who added a overridden a method in a mid-level Class know that their change will affect child classes.
Also, I was talking to someone who said that there might be library already out there that does this.
I'm looking for thoughts and examples of how to write tests to handle this scenario. Refactoring is not an option in this case.

Sorry, but the proper answer to a bad design is not to "fix" it by coming up with "interesting" unit tests.
You fix a bad design by fixing the bad design.
In other words: the very first thing about OO to understand is LSP (Liskov substitution principle). In other words: when your developers change something in "the middle" of your inheritance tree, and that causes unexpected behavior in child classes further down, then you should rather invest in education and design sessions.
Beyond that, you don't need specific testing. When all public methods of your public classes are thoroughly tested, then you should quickly catch such kind of problems. But there is no way to determine pro grammatically that you have good tests for all classes. The fact that there are n test methods for some method X ... doesn't tell anything about the quality of any of the test methods. It doesn't help to know that you have "enough" tests ... but sorry, unfortunately, half of the tests isn't doing proper checking/verification; and thus they just keep passing all the time.
Long story short: you are looking at an XY problem here. Your Y problem is "our tests don't fail when we mess up code". But your X problem is: you created a bad design in the first place; and now you are searching for ways to work around that. And that will simply not work out in the long run.

Related

Inheritance chain vs multiple extensions

Is inheritance chaining something that should be avoided?
I'm currently in the process of refactoring a java project and I have come across a number of classes (8) which all of them have a shared functionality. So, using the Extract Super Class refactoring, I created a super class with that functionality and passed it to all the sub-classes. Now, 2 of the classes have also a second shared functionality. Should I create another super class which inherits from the first super class and, in turn, is extended by the sub-classes or simply extend multiple classes on the 2 sub-classes?
Thoughts
Even though both options would work, I feel that going for multiple extensions is preferable since it describes and clarifies the responsibilities of the class. Also, we would avoid making continuous super() calls in order to reach the top super class.
On the other hand, maybe having an inheritance chain kinda tidies up the place.
Edit: I understand I stated my problem completely wrong. The 8 classes that are mentioned above are made to abide by the command pattern and as such each one has a different purpose and functionality. I have extracted a super class to avoid code duplication inside their constructors. Two of those classes have also have a little bit more duplicate code (not duplicate functionality, in the sense that they do the same thing). Unfortunately, due to the nature of the project, the fact that I did not write the original code and the tight time schedule do not allow me to completely reconstruct the whole project. It's, let's say, beyond repair for now. But what I can do is patchwork to try to remove duplicate code and tidy the place up a bit.
Super classes should be used when they model a is-a relationship. If the 8 classes are the same entity, a common super class can be used to avoid duplication. Class hierarchies can hurt maintainability quickly and should be as simple as possible. Avoiding duplicate code is not the main concern when introducing them.
As #davidza5 already pointed out, the principle of composition over inheritance applies here. Common functionality should preferably be extracted into classes that model a has-a relationship, which decouples functionality and makes it easier to change later on.
Another aspect: if a refactoring does not work in all cases this does not mean it is the wrong idea. If it leads to good results for the majority, working around the quirks of the exceptions is a good trade off to make.
Both methods seems to be a bad practice in most cases (favorize composition over inheritance). If you can avoid it by using design patterns (facade, composite, adapter,decorator...). If it can't be done in your case the principle of encapsulation and inheritance is what I would apply. So, when necessary chain inheritance.

How to testing something like a converter

i have a question regarding testing classes like a converter.
Lets say i have a converter from EntityA to EntityB. The converter seems like this:
public EntityB convert(EntityA){
//call interal methods
return B.
}
private xy internalMethod1(...){
//call other interal Method
}
private xy internalMethod2(...){
....
}
private xy internalMethod3(...){
....
}
private xy internalMethod4(...){
....
}
The converter has one public method and 4 internal methods to convert the entity.
How should i test it?
Option1
I only test the public method and cover all cases from the internalMethods by different example inputs.
Advantages:
Testing only the "interface". Dont know the interal structure.
Internal refactoring is very easy and needs no changes at the tests.
Disadvantages:
Really big maybe unclear tests that tests all cases.
Every input must be pass all the methods.
Option2
I write tests for my public method and my private methods. (Some testframeworks can access private methods like powermock or spock (groovy))
I test every method alone and mock every other internal method.
Advantages:
Really small tests that only test the method itself and mock all other methods .
Disadvantages:
I know how it is implemented internal and must change the tests if i refactor some method, some methodname or something at the internal calling structure
Option3
I write some new classes that do the internal stuff and have public methods
Advantages:
Tests are maybe clearer and only for the special classes.
Disadvantages:
More classes for one conversion task.
Please help me what is the best practise here.
Maybe some good links/hints.
Thank you for your time.
The points you make are valid, but I think you might not be estimating their weight correctly.
Writing brittle tests (tests that are coupled to the implementation code) makes for a rigid code base that is hard to change. Since the point of writing tests in the first place is to be able to go fast, this is counter productive.
This is why you write your tests through the API only - it decouples the tests from the implementation. As you've said, this might make writing the tests a bit harder, but the reward is worth the effort since you'll get safety and be able to refactor easily.
Option 3 comes into play when you see a code smell where some tests cover only some of the code, and other tests only cover the other part of the code. This usually means there's a collaborator that maybe needs to be extracted. This is especially true when some internal functions only use some parameters and others don't. Also, when there's code duplication and the like.
What I would suggest, is to write it using the way you described in option 1, and then extract code out if needed, in the refactoring stage.

Creating a testing class for a strange program

I have completed my project, but cannot get the testing class to work. I know this is because i wrote the code in probably the worst possible way. However, it's too late to change now, and honestly i don't want too either. Could someone suggest a possible way of a testing class based on the code i currently have...
Your code is untestable. You need to use more object oriented way of programming. Try to refactor code into few shorter methods. Then you can test separate methods.
For unit testing I recommend Junit
Your code might work because you extend Pizza and then in your main you just set the static attributes. But there is absolutely nothing you could test here, as you have 0 methods and 0 objects.
You can't even instantiate your Pizza class, as all its attributes are static and an instance would therefore be useless.
All you can test is assigning values to static attributes, but I guess we can expect that to be bugfree ;-)

Good software design practise

I have a big class, which is used on the user interface of an application. It serves around 20 modules. For only one Module for the time being I need a different formation of number on a Label. The applying of formation is programatically only a line of source code. The separation of the cases can be done either by the use of a boolean flag variable, or by applying inheritance:
By boolean flag variable:
class MyClass{
private boolean isYear;
...
public setValue(){
...
if(!isYear)
doFormat();
...
}
}
The variable isYear is set of course externally, when a module serves for year valus is needed.
By applying inheritance I have to create a new class which derives from MyClass, i.e. MyYearClass and merely override the method setValue(). I think in the OO-programming the second approach is recommended, but I have heard also the opinion that in this case it makes the code complicated, more nebulous, less neat and it seems generally an overkill when only one line of code is to be changed. What approach do you consider recommendable?
As always, it depends. It can be one line now but maybe a lot more later. I agree that overengineering your code is bad but if you feel that the current design will change (and it usually does) you can use a simple design pattern here and there. For your problem (described shortly) I believe you can create a simple Factory and have that factory return for you one of the subclasses of MyClass you need when you need it.
Good design practices will favour the second method (inheritance) as it is easier to manage in the long run. When you start adding specific code to a common class, you are opening a can of worms. Maybe not you, but a developer working after you will add another feature, and another feature to the same class and then support becomes a nightmare.
What worries me more is your "I have a big class" quote. Good design principles will tell you to break it apart.
If your class has more than, say, 1000 lines, it's a good candidate for refactoring into specific functionalities.
The second approach is really better generally. But in your case you have a small class with simple logic. If you know that you are going to change this class a lot and it will become bigger and more complicated, then split it now. Otherwise you might leave it as it is, and postpone the refactoring for a future moment if you feel the class becomes too complicated. Instead, focus on other part of your application.
I think the second approach is the best practice. It might seem a bit superfluous but it is always best to keep your programming as modular as possible. Just imagine if someone else was using your code or you were using it later on and couldn't exactly remember how the MyClass worked but all you wanted to do was use the functionality of MyYearClass.

Java: Best practices for turning foreign horror-code into clean API...?

I have a project (related to graph algorithms). It is written by someone else.
The code is horrible:
public fields, no getters/setters
huge methods, all public
some classes have over 20 fields
some classes have over 5 constructors (which are also huge)
some of those constructors just leave many fields null
(so I can't make some fields final, because then every second constructor signals errors)
methods and classes rely on each other in both directions
I have to rewrite this into a clean and understandable API.
Problem is: I myself don't understand anything in this code.
Please give me hints on analyzing and understanding such code.
I was thinking, perhaps, there are tools which perform static code analysis
and give me call graphs and things like this.
Oh dear :-) I envy you and not at the same time..ok let's take one thing at a time. Some of these things you can tackle yourself before you set a code analyzing tool loose at it. This way you will gain a better understanding and be able to proceed much further than with a simple tool
public fields, no getters/setters
make everything private. Your rule should be to limit access as much as possible
huge methods, all public
split and make private where it makes sense to do so
some classes have over 20 fields
ugh..the Builder pattern in Effective Java 2nd Ed is a prime candidate for this.
some classes have over 5 constructors (which are also huge)
Sounds like telescoping constructors, same pattern as above will help
some of those constructors just left many fields null
yep it is telescoping constructors :)
methods and classes rely on each other in both directions
This will be the least fun. Try to remove inheritance unless you're perfectly clear
it is required and use composition instead via interfaces where applicable
Best of luck we are here to help
WOW!
I would recommend: write unittests and then start refactoring
* public fields, no getters/setters
start by making them private and 'feel' the resistance on compiler errors as metric.
* huge methods, all public
understand their semantics, try to introdue interfaces
* some classes have over 20 fields
very common in complex appilcations, nothing to worrie
* some classes have over 5 constructors (which are also huge)
replace them by by buider/creator pattern
* some of those constructors just left many fields null
see above answer
* methods and classes rely on each other in both directions
decide whether to to rewrite everything (honestly I faced cased where only 10% of the code was needed)
Well, the clean-up wizard in eclipse will scrape off a noticable percentage of the sludge.
Then you could point Sonar at it and fix everything it complains about, if you live long enough.
For static analysis and call graphs (no graphics, but graph structures), you can use Dependency Finder.
Use an IDE that knows something about refactoring, like IntelliJ. You won't have situations where you move one method and five other classes complain, because IntelliJ is smart enough to make all the required changes.
Unit tests are a must. Someone refactoring without unit tests is like a high-wire performer without a safety net. Get one before you start the long, hard climb.
The answer may be: patience & coffee.
This is the way I would do it:
Start using the code , e.g. from within a main method, as if it were used by the other classes - same arguments, same invocation orders. Do that inside a debugger, as you see each step that this class makes.
Start writing unit tests for that functionality. Once you have reached a reasonable coverage, you will start to notice that this class probably has too many responsibilities.
while ( responsibilities != 1 ) {
Extract an interface which expresses one responsibility of that class.
Make all callers use that interface instead of the concrete type;
Extract the implementation to a separate class;
Pass the new class to all callers using the new interface.
}
Not saying tools like Sonar, FindBugs etc. that some have already mentiones don't help, but there are no magic tricks. Start from something you do understand, create a unit test for it and once it runs green start refactoring piece by piece. Remember to mock dependencies as you go along.
Sometimes it is easier to rewrite something from scratch. Is this 'horrible code' working as intended or full of bugs? It is documented?
In my current project, deleting my predessor's work nearly in its entirety, and rewriting it from scratch, was the most efficient approach. Granted, this was an extreme case of code obfuscation, utter lack of meaningful comments, and utter incompetence, so your mileage may vary.
Though some legacy code might be barely comprehensible, still it can be refactored and improved to legibility in a stepwise fashion. Have you seen Joshua Kerievsky's Refactoring To Patterns book? -- it's good on this.

Categories