Code Without Tests

Posted on Posted in programming

You have a test coverage 90% or more but not 100%. You have tests that cover all exceptional cases. What about code that is not covered with tests?

Example: code that is hard to delete

Let’s say, that we have an interface with two methods:

public interface MyInterface {
    Foo getFoo();
    
    Bar getBar();
}

and for it implementation MyInterfaceImplA. Latter we have to implement the interface with a different implementation. We create a test for method getFoo and an implementation in a new class MyInterfaceImplB. In order to run the test we have to compile classes. But we can’t compile class MyInterfaceImplB, because it doesn’t implement the interface fully. In class MyInterfaceImplB we create a new method getBar() with a dummy implementation.

public class MyInterfaceImplB implements MyInterface {
    @Override
    public Foo getFoo() {
        return new Foo();  // implementation
    }
    @Override
    public Bar getBar() {
        return null;
    }  // dummy implementation
}

Now we run tests and tests are successfully executed. Then we run the test coverage and the test coverage is not 100%. If we deleted code that was not hit by tests, the program wouldn’t compile anymore.

We could write a test for getBar method when we wrote a test for getFoo method. But when we have larger interface, do we think first about specification for all methods and then implement them or we think first about specification for one method and then implement it?

We can write tests for a implementation that throw unsupported operation exception.

public class MyInterfaceImplB implements MyInterface {
    @Override
    public Foo getFoo() {
        return new Foo();  // implementation
    }
    @Override
    public Bar getBar() {
        throw new UnsupportedOperationException();
    }   // implementation
}

Example: generated code

Generated code looks like that it can be without tests. If a generator works correctly, why would we test generated code?

Class with generated methods setters and getters, equals and hashCode, toString:

public class Bar {
    Foo foo;
    public Foo getFoo() {
        return foo;
    }
    public void setFoo(Foo foo) {
        this.foo = foo;
    }
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Bar bar = (Bar) o;
        return Objects.equals(foo, bar.foo);
    }
    @Override
    public int hashCode() {
        return Objects.hash(foo);
    }
    @Override
    public String toString() {
        return "Bar{" +
                "foo=" + foo +
                '}';
    }
}

We don’t know that code is 100% generated. It could be changed later.

Generator may provide options. For example, when you create methods like equals and hashCode is very important which attributes you chose.

Conclusion

If code is not covered with test, then there is no guarantee that code works as specified or it will work as specified.

Leave a Reply