[JAVA] How to exclude auto-generated from Jacoco coverage when using Lombok

Overview

This entry assumes that you are using Lombok, which generates the source code, and the coverage measurement tool Jacoco. I will prepare a sample and introduce how to increase the coverage in).

The purpose of this entry is to help you get started when you want to use Lombok with as little code as possible and increase coverage with Jacoco. It does not explain all the functions of each tool.

Conclusion

In conclusion, let's exclude the automatically generated code from the coverage inspection target by specifying "lombok.addLombokGeneratedAnnotation = true" on the lombok side using Jacoco 0.8.0 (released 1/2/2018) or higher. , Is a big point.

Reference entry

In Qiita, about Lombok, Jacoco,

-[Search by Qiita](https://qiita.com/search?utf8= ✓ & sort = & q = lombok), there were 347.

-[Search by Qiita](https://qiita.com/search?utf8= ✓ & sort = & q = jacoco), there were 79.

There are many (as of May 26, 2018), but the following will be helpful.

-Make Java code coverage more comfortable with Jacoco 0.8.0

Initial sample

As a sample, I made a Spring Boot that stores and displays simple entities through a REST Controller.

It works like this.

(Registration)
$ curl -H 'Content-Type:application/json' -d '{"intField":123}' http://localhost:8080

(reference)
$ curl http://localhost:8080/ 
[{"id":"2815cfc6-f908-4c7d-a20b-b2c52953555f","intField":123,"longField":0,"stringField":null,"charField"

(1 detail)
$ curl http://localhost:8080/2815cfc6-f908-4c7d-a20b-b2c52953555f
{"id":"2815cfc6-f908-4c7d-a20b-b2c52953555f","intField":123,"longField":0,"stringField":null,"charField":"\u0000","byteField":0}hirokis-M

It is stored in Initial repository.

In this version, it is implemented without using the convenient functions of lombok.

$ ./gradlew test
$ ./gradlew jacocoTestReport

The coverage looks like this. スクリーンショット 2018-05-26 14.39.51.png

lombok application

@ Data

SampleEntity before application

SampleEntity.java


public class SampleEntity {
    private SampleId id;
    private int intField;
    private long longField;
    private String stringField;
    private char charField;
    private byte byteField;
    /**
     * @return the id
     */
    public SampleId getId() {
        return id;
    }
    /**
     * @param id the id to set
     */
    public void setId(SampleId id) {
        this.id = id;
    }
    /**
     * @return the intField
     */
    public int getIntField() {
        return intField;
    }
    /**
     * @param intField the intField to set
     */
    public void setIntField(int intField) {
        this.intField = intField;
    }
    /**
     * @return the longField
     */
    public long getLongField() {
        return longField;
    }
    /**
     * @param longField the longField to set
     */
    public void setLongField(long longField) {
        this.longField = longField;
    }
    /**
     * @return the stringField
     */
    public String getStringField() {
        return stringField;
    }
    /**
     * @param stringField the stringField to set
     */
    public void setStringField(String stringField) {
        this.stringField = stringField;
    }
    /**
     * @return the charField
     */
    public char getCharField() {
        return charField;
    }
    /**
     * @param charField the charField to set
     */
    public void setCharField(char charField) {
        this.charField = charField;
    }
    /**
     * @return the byteField
     */
    public byte getByteField() {
        return byteField;
    }
    /**
     * @param byteField the byteField to set
     */
    public void setByteField(byte byteField) {
        this.byteField = byteField;
    }
    /* (non-Javadoc)
     * @see java.lang.Object#hashCode()
     */
    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + byteField;
        result = prime * result + charField;
        result = prime * result + ((id == null) ? 0 : id.hashCode());
        result = prime * result + intField;
        result = prime * result + (int) (longField ^ (longField >>> 32));
        result = prime * result
                + ((stringField == null) ? 0 : stringField.hashCode());
        return result;
    }
    /* (non-Javadoc)
     * @see java.lang.Object#equals(java.lang.Object)
     */
    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        SampleEntity other = (SampleEntity) obj;
        if (byteField != other.byteField)
            return false;
        if (charField != other.charField)
            return false;
        if (id == null) {
            if (other.id != null)
                return false;
        } else if (!id.equals(other.id))
            return false;
        if (intField != other.intField)
            return false;
        if (longField != other.longField)
            return false;
        if (stringField == null) {
            if (other.stringField != null)
                return false;
        } else if (!stringField.equals(other.stringField))
            return false;
        return true;
    }
    /**
     * @param id
     * @param intField
     * @param longField
     * @param stringField
     * @param charField
     * @param byteField
     */
    public SampleEntity(SampleId id, int intField, long longField,
            String stringField, char charField, byte byteField) {
        super();
        this.id = id;
        this.intField = intField;
        this.longField = longField;
        this.stringField = stringField;
        this.charField = charField;
        this.byteField = byteField;
    }

    public SampleEntity() {
        super();
    };

}
It looks like this.

SampleEntity.java


@Data
public class SampleEntity {
    private SampleId id;
    private int intField;
    private long longField;
    private String stringField;
    private char charField;
    private byte byteField;
}

If you check in the IDE with the lombok plugin applied (Eclipse in this entry), you can see that the setter, getter, toString, and hashCode are generated.

スクリーンショット 2018-05-26 14.53.59.png

@ RequiredArgsConstructor

When injecting a field with @Autowired of Spring, it may be troublesome to replace it directly for testing etc., or it may take up space when there are many things to use, so inject it with the constructor. I will change it.

SampleApi.java before application is

SampleApi.java


@RestController
@RequestMapping("/")
public class SampleApi {
    @Autowired
    private SampleFacade sampleFacade;
    
It looks like this.
Note that the field is final.

SampleApi.java


@RestController
@RequestMapping("/")
@RequiredArgsConstructor
public class SampleApi {
    private final SampleFacade sampleFacade;    

So far, the jacoco Report looks like this.

スクリーンショット 2018-05-26 15.10.35.png

Here, the domain package is a good proportion, but if you look inside, it is naturally the code automatically generated by lombok. When the behavior of lombok is positive, it doesn't make much sense to test what is generated.

スクリーンショット 2018-05-26 15.07.45.png

For this reason, let's specify to exclude the code generated by Lombok from the test. Place the following files in the project directory and try the test again.

lombok.config


lombok.addLombokGeneratedAnnotation = true 
$ ./gradlew clean
$ ./gradlew test
$ ./gradlew jacocoTestReport 

And the coverage changes like this. The red situation hasn't changed since I haven't written the test code yet, but the domain area has been greatly reduced, and the overall code instructions have been significantly reduced from 731 to 170.

スクリーンショット 2018-05-26 15.17.31.png

A description of the values that can be specified in lombok.config can be found on the lombok official website.

I put the above as v0.2 on GitHub.

Add test

In the unit test, the coverage is set to 100% by passing 1 pass for the time being Sample on GitHub v0.3 It will be /releases/tag/v0.3).

スクリーンショット 2018-05-26 17.09.12.png

(Reference) Now, if you restore (do not specify) the exclusion setting, this situation will occur.

スクリーンショット 2018-05-26 17.13.05.png

Summary

In this entry, I saw how to exclude the code automatically generated by lombok from the coverage measurement, and showed through the sample code how it actually works.

In addition to using the lombok function in the sample of this entry, Various on the original site has been introduced, so I would like to introduce a usage example at another time. think.

Recommended Posts

How to exclude auto-generated from Jacoco coverage when using Lombok
How to add characters to display when using link_to method
How to test including images when using ActiveStorage and Faker
How to set environment variables when using Payjp with Rails
How to use @Builder (Lombok)
How to write and notes when migrating from VB to JAVA
How to write query option when using gem ruby-firebase (memorial)
Output JaCoCo coverage to console
How to use Lombok now
How to migrate from JUnit4 to JUnit5
How to authorize using graphql-ruby
I can't log in to MySQL from Django when using docker-compose
How to delete only specific data from data created using Form object
How to solve the unknown error when using slf4j in Java
[Rails 5] How to display the password change screen when using devise
How to push from Tarminal to GitHub
How to set Lombok in Eclipse
How to build CloudStack using Docker
How to change from HTML to Haml
How to return a value from Model to Controller using the [Swift5] protocol
[Android] How to pass images and receive callbacks when sharing using ShareCompat
How to sort a List using Comparator
[Rails] How to convert from erb to haml
[Rails] How to upload images using Carrierwave
[Java] How to calculate age using LocalDate
[IOS] How to get data from DynamoDB
How to resolve errors when installing Rails 5.1.3
Story when moving from Spring Boot 1.5 to 2.1
Connect from Java to MySQL using Eclipse
[Flutter] How to use C / C ++ from Dart?
Changes when migrating from Spring Boot 1.5 to Spring Boot 2.0
Java: How to send values from Servlet to Servlet
Changes when migrating from Spring Boot 2.0 to Spring Boot 2.2
Precautions when migrating from VB6.0 to JAVA
[Swift5] How to implement animation using "lottie-ios"
How to implement image posting using rails
How to make asynchronous pagenations using Kaminari
[Rails] How to handle data using enum
Troubleshooting when raising Mastodon from v3.0.x to v3.1.x
How to insert icons using Font awesome
How to get the query string to actually issue when using PreparedStatement with JDBC