Is it possible to run class unit test with inheritance?

Asked

Viewed 471 times

3

I need to do a unit test of PlanilhaReader but this extension ArrayList<String> and override the method contains. Is there any way to execute it?

@Component
public class PlanilhaReader extends ArrayList<String> {

    final String UPLOAD_PATH = PropertiesSingleton.getValue("api.upload.dir");

    @Override
    public boolean contains(Object o) {
        String paramStr = (String)o;
        for (String s : this) {
            if (paramStr.equalsIgnoreCase(s)) return true;
        }
        return false;
    }

    public BasicDBList readMetadados(Planilha planilha) {...}
}

Testing

public class PlanilhaReaderTest {

    @Test
    public void testReadMetadados() throws Exception {
        PlanilhaReader reader = new PlanilhaReader();
        Planilha planilha = new Planilha().setPath("552d4cf1ccf2c0a58301a744/55163343b0df070bbc66e1bb6e0c3f9b.xlsx");
        reader.readMetadados(planilha);
    }
}

When compiling I get the error:

Hot Swap failed
         Tomcat 8.0.18: hierarchy change not implemented; 
         Tomcat 8.0.18: Operation not supported by VM; 
         PlanilhaReaderTest: hierarchy change not implemented; 
         PlanilhaReaderTest: Operation not supported by VM; 
         PlanilhaReaderTest: hierarchy change not implemented; 
         PlanilhaReaderTest: Operation not supported by VM
  • 1

    Silly question? Because she inherits from ArrayList<String>? That sounds like a bad idea!

  • Because of the "contains", I need it not to be case sensitive.

1 answer

2


Inherit from ArrayList<String> is bad. Incidentally inheriting from any class of Collection, unless you know very well what you’re doing is bad. The reason is that the Collections is out of your control and inheriting from one of them something bad might happen.

Is it possible to test your subclass properly? Yes. Is it easy to do that? No. The reason is that your subclass relies heavily on the superclass. In your case, in doing so, yours Collection can create some unexpected behaviors. For example:

if (lista.contains("abacaxi")) lista.remove("abacaxi");

This will mysteriously fail if what is on your list is "PINEAPPLE" instead of "pineapple". This is because superclass behavior has some implicit conditions that the subclass innocently ends up violating.

In fact, it’s possible to fix your subclass. But in practice you’ll have to introduce a lot of different changes and eventually rewrite the entire superclass within the subclass and probably that’s not what you want.

On the other hand, you will probably argue that you only use this class for a specific purpose and that it does not need all the functionalities inherited from the superclass. In this case, what you inherit from the superclass is called goddamn inheritance, behaviors that are unwanted in the subclass and are there because they came from the superclass.

What is the solution to this? Abandon heritage and use composition:

@Component
public class PlanilhaReader {

    final String UPLOAD_PATH = PropertiesSingleton.getValue("api.upload.dir");

    private final List<String> lista;

    public PlanilhaReader() {
        lista = new ArrayList<>(10);
    }

    public boolean contains(String paramStr) {
        return this.lista.contains(paramStr.toLowerCase(Locale.ROOT));
    }

    public void add(String s) {
        this.lista.add(s.toLowerCase(Locale.ROOT));
    }

    public BasicDBList readMetadados(Planilha planilha) {...}
}

And as a result, your class is now much easier to test. The number of interactions between data and methods in this class is much lower. It is also much harder to use it inappropriately or unexpectedly.

Note that to simplify, I decided to put all the elements in the list already converted to a canonical form in order to do the contains original work.

  • I had to deal with it that way so I could take the test. Disregarding this specific situation, it is not possible to carry out unit tests in "daughter" classes, so?

  • 3

    @Danielamarquesdemorais Yes, but you always have to keep in mind that all the behaviors of the parent class are there together. And unless you know very well what you’re doing, some of these parent-class behaviors might get in your way. After all, today class inheritance is considered a bad thing in object orientation, as it promotes high coupling rather than low coupling. Inheritance is something to be avoided unless you have a strong reason to use.

  • 1

    I spent so much of my life solving problems that I created by inheriting the C#... Damn object-oriented "school" that presents heritage as the coolest resource and "must have" for your code.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.