Wie füge ich einem privaten Konstruktor eine Testabdeckung hinzu?

110

Dies ist der Code:

package com.XXX;
public final class Foo {
  private Foo() {
    // intentionally empty
  }
  public static int bar() {
    return 1;
  }
}

Dies ist der Test:

package com.XXX;
public FooTest {
  @Test 
  void testValidatesThatBarWorks() {
    int result = Foo.bar();
    assertEquals(1, result);
  }
  @Test(expected = java.lang.IllegalAccessException.class)
  void testValidatesThatClassFooIsNotInstantiable() {
    Class cls = Class.forName("com.XXX.Foo");
    cls.newInstance(); // exception here
  }
}

Funktioniert gut, die Klasse wird getestet. Cobertura sagt jedoch, dass der private Konstruktor der Klasse keine Codeabdeckung aufweist. Wie können wir einem solchen privaten Konstruktor eine Testabdeckung hinzufügen?

yegor256
quelle
Es scheint mir, als ob Sie versuchen, das Singleton-Muster durchzusetzen. Wenn ja, könnte Ihnen dp4j.com gefallen (was genau das tut)
simpatico
sollte "absichtlich leer" nicht durch eine Ausnahmeregelung ersetzt werden? In diesem Fall könnten Sie einen Test schreiben, der diese bestimmte Ausnahme mit einer bestimmten Nachricht erwartet, nein? Ich
bin

Antworten:

84

Nun, es gibt Möglichkeiten, wie Sie möglicherweise Reflexion usw. verwenden können - aber lohnt es sich wirklich? Dies ist ein Konstruktor, der niemals aufgerufen werden sollte , oder?

Wenn es eine Anmerkung oder ähnliches gibt, die Sie der Klasse hinzufügen können, damit Cobertura versteht, dass sie nicht aufgerufen wird, tun Sie Folgendes: Ich denke, es lohnt sich nicht, durch Reifen zu gehen, um die Berichterstattung künstlich hinzuzufügen.

EDIT: Wenn es keine Möglichkeit gibt, leben Sie einfach mit der leicht reduzierten Abdeckung. Denken Sie daran, dass die Abdeckung für Sie nützlich sein soll - Sie sollten für das Tool verantwortlich sein, nicht umgekehrt.

Jon Skeet
quelle
18
Ich möchte die Abdeckung im gesamten Projekt nicht nur wegen dieses speziellen Konstruktors "leicht reduzieren".
yegor256
35
@ Vincenzo: Dann legen Sie IMO einen zu hohen Wert auf eine einfache Zahl. Die Abdeckung ist ein Indikator für Tests. Sei kein Sklave eines Werkzeugs. Der Punkt der Berichterstattung besteht darin, Ihnen ein gewisses Maß an Vertrauen zu geben und Bereiche für zusätzliche Tests vorzuschlagen. Das künstliche Aufrufen eines ansonsten nicht verwendeten Konstruktors hilft bei keinem dieser Punkte.
Jon Skeet
19
@ JonSkeet: Ich stimme voll und ganz zu "Sei kein Sklave eines Werkzeugs", aber es riecht nicht gut, sich an jede "Fehleranzahl" in jedem Projekt zu erinnern. Wie kann sichergestellt werden, dass das 7/9-Ergebnis eine Cobertura-Einschränkung ist und nicht das eines Programmierers? Ein neuer Programmierer muss jeden Fehler eingeben (der in großen Projekten sehr häufig sein kann), um Klasse für Klasse zu überprüfen.
Eduardo Costa
5
Dies beantwortet die Frage nicht. Übrigens sehen sich einige Manager die Deckungszahlen an. Es ist ihnen egal warum. Sie wissen, dass 85% besser sind als 75%.
ACV
2
Ein praktischer Anwendungsfall zum Testen von ansonsten unzugänglichem Code besteht darin, eine 100% ige Testabdeckung zu erreichen, damit niemand diese Klasse erneut betrachten muss. Wenn die Abdeckung bei 95% bleibt, versuchen viele Entwickler möglicherweise, den Grund dafür herauszufinden, um immer wieder auf dieses Problem zu stoßen.
Thisismydesign
140

Ich stimme Jon Skeet nicht ganz zu. Ich denke, wenn Sie einen einfachen Gewinn erzielen können, um Berichterstattung zu erhalten und das Rauschen in Ihrem Bericht zu beseitigen, sollten Sie dies tun. Weisen Sie entweder Ihr Coverage-Tool an, den Konstruktor zu ignorieren, oder legen Sie den Idealismus beiseite und schreiben Sie den folgenden Test und fertig damit:

@Test
public void testConstructorIsPrivate() throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
  Constructor<Foo> constructor = Foo.class.getDeclaredConstructor();
  assertTrue(Modifier.isPrivate(constructor.getModifiers()));
  constructor.setAccessible(true);
  constructor.newInstance();
}
Javid Jamae
quelle
24
Dadurch wird jedoch das Rauschen im Abdeckungsbericht beseitigt, indem der Testsuite Rauschen hinzugefügt wird . Ich hätte den Satz gerade mit "den Idealismus beiseite legen" beendet. :)
Christopher Orr
11
Um diesem Test eine Bedeutung zu geben, sollten Sie wahrscheinlich auch behaupten, dass die Zugriffsebene des Konstruktors so ist, wie Sie es erwarten.
Jeremy
Wenn ich das böse Spiegelbild plus Jeremys Ideen und einen bedeutungsvollen Namen wie "testIfConstructorIsPrivateWithoutRaisingExceptions" hinzufüge, denke ich, dass dies "DIE" Antwort ist.
Eduardo Costa
1
Das ist syntaktisch falsch, nicht wahr? Was ist constructor? Sollte nicht Constructorparametriert werden und kein Rohtyp?
Adam Parkin
2
Dies ist falsch: constructor.isAccessible()Gibt auch bei einem öffentlichen Konstruktor immer false zurück. Man sollte verwenden assertTrue(Modifier.isPrivate(constructor.getModifiers()));.
Timomeinen
78

Obwohl es sich nicht unbedingt um eine Abdeckung handelt, habe ich diese Methode erstellt, um zu überprüfen, ob die Dienstprogrammklasse gut definiert ist, und um auch eine gewisse Abdeckung durchzuführen.

/**
 * Verifies that a utility class is well defined.
 * 
 * @param clazz
 *            utility class to verify.
 */
public static void assertUtilityClassWellDefined(final Class<?> clazz)
        throws NoSuchMethodException, InvocationTargetException,
        InstantiationException, IllegalAccessException {
    Assert.assertTrue("class must be final",
            Modifier.isFinal(clazz.getModifiers()));
    Assert.assertEquals("There must be only one constructor", 1,
            clazz.getDeclaredConstructors().length);
    final Constructor<?> constructor = clazz.getDeclaredConstructor();
    if (constructor.isAccessible() || 
                !Modifier.isPrivate(constructor.getModifiers())) {
        Assert.fail("constructor is not private");
    }
    constructor.setAccessible(true);
    constructor.newInstance();
    constructor.setAccessible(false);
    for (final Method method : clazz.getMethods()) {
        if (!Modifier.isStatic(method.getModifiers())
                && method.getDeclaringClass().equals(clazz)) {
            Assert.fail("there exists a non-static method:" + method);
        }
    }
}

Ich habe den vollständigen Code und die Beispiele in https://github.com/trajano/maven-jee6/tree/master/maven-jee6-test platziert

Archimedes Trajano
quelle
11
+1 Dies löst nicht nur das Problem, ohne das Tool auszutricksen, sondern testet auch die Codierungsstandards zum Einrichten einer Utility-Klasse vollständig. Ich musste den Barrierefreiheitstest ändern, um ihn zu verwenden, Modifier.isPrivateda isAccessibleer truein einigen Fällen für private Konstruktoren zurückgegeben wurde (spöttische Bibliotheksinterferenz?).
David Harkness
4
Ich möchte dies wirklich zu JUnits Assert-Klasse hinzufügen, aber ich möchte Ihre Arbeit nicht würdigen. Ich finde es sehr gut. Es wäre toll, Assert.utilityClassWellDefined()in JUnit 4.12+ zu haben . Haben Sie eine Pull-Anfrage in Betracht gezogen?
Visionary Software Solutions
Beachten Sie, dass die Verwendung setAccessible(), um den Konstruktor zugänglich zu machen, Probleme für das Codeabdeckungstool von Sonar verursacht (wenn ich dies tue, verschwindet die Klasse aus den Codeabdeckungsberichten von Sonar).
Adam Parkin
Danke, ich setze die zugängliche Flagge zurück. Vielleicht ist es ein Fehler bei Sonar selbst?
Archimedes Trajano
Ich habe in meinem Sonar-Bericht nach Informationen zu meinem Batik-Maven-Plugin gesucht. Es scheint korrekt zu sein. site.trajano.net/batik-maven-plugin/cobertura/index.html
Archimedes Trajano
19

Ich hatte den Konstruktor meiner Klasse statischer Dienstprogrammfunktionen privat gemacht, um CheckStyle zu erfüllen. Aber wie auf dem Originalplakat hatte ich Cobertura, der sich über den Test beschwerte. Zuerst habe ich diesen Ansatz ausprobiert, aber dies hat keine Auswirkungen auf den Abdeckungsbericht, da der Konstruktor nie tatsächlich ausgeführt wird. Diese Tests werden also wirklich nur durchgeführt, wenn der Konstruktor privat bleibt - und dies wird durch die Zugänglichkeitsprüfung im nachfolgenden Test überflüssig.

@Test(expected=IllegalAccessException.class)
public void testConstructorPrivate() throws Exception {
    MyUtilityClass.class.newInstance();
    fail("Utility class constructor should be private");
}

Ich folgte dem Vorschlag von Javid Jamae und benutzte Reflexion, fügte aber Behauptungen hinzu, um jemanden zu erwischen, der mit der getesteten Klasse herumspielt (und nannte den Test, um High Levels Of Evil anzuzeigen).

@Test
public void evilConstructorInaccessibilityTest() throws Exception {
    Constructor[] ctors = MyUtilityClass.class.getDeclaredConstructors();
    assertEquals("Utility class should only have one constructor",
            1, ctors.length);
    Constructor ctor = ctors[0];
    assertFalse("Utility class constructor should be inaccessible", 
            ctor.isAccessible());
    ctor.setAccessible(true); // obviously we'd never do this in production
    assertEquals("You'd expect the construct to return the expected type",
            MyUtilityClass.class, ctor.newInstance().getClass());
}

Das ist so übertrieben, aber ich muss zugeben, dass ich das warme, verschwommene Gefühl einer 100% igen Methodenabdeckung mag.

Ben Hardy
quelle
Overkill mag es sein, aber wenn es in Unitils oder ähnlichem wäre, würde ich es benutzen
Stewart
+1 Guter Start, obwohl ich mich für Archimedes 'vollständigeren Test entschieden habe .
David Harkness
Das erste Beispiel funktioniert nicht - die IllegalAccesException bedeutet, dass der Konstruktor niemals aufgerufen wird, sodass keine Abdeckung aufgezeichnet wird.
Tom McIntyre
IMO, die Lösung im ersten Code-Snippet ist die sauberste und einfachste in dieser Diskussion. Nur Linie mit fail(...)ist nicht notwendig.
Piotr Wittchen
9

Mit Java 8 ist es möglich, andere Lösungen zu finden.

Ich gehe davon aus, dass Sie einfach eine Utility-Klasse mit wenigen öffentlichen statischen Methoden erstellen möchten. Wenn Sie Java 8 verwenden können, können Sie interfacestattdessen verwenden.

package com.XXX;

public interface Foo {

  public static int bar() {
    return 1;
  }
}

Es gibt keinen Konstruktor und keine Beschwerde von Cobertura. Jetzt müssen Sie nur noch die Linien testen, die Ihnen wirklich wichtig sind.

Arnost Valicek
quelle
1
Leider können Sie die Schnittstelle nicht als "endgültig" deklarieren, sodass niemand sie unterordnen kann. Andernfalls wäre dies der beste Ansatz.
Michael Berry
5

Der Grund für das Testen von Code, der nichts bewirkt, besteht darin, eine 100% ige Codeabdeckung zu erreichen und festzustellen, wann die Codeabdeckung abnimmt. Ansonsten könnte man immer denken, hey ich habe keine 100% ige Codeabdeckung mehr, aber es ist wahrscheinlich wegen meiner privaten Konstruktoren. Dies macht es einfach, nicht getestete Methoden zu erkennen, ohne überprüfen zu müssen, ob es sich nur um einen privaten Konstruktor handelt. Wenn Ihre Codebasis wächst, fühlen Sie tatsächlich ein angenehm warmes Gefühl, wenn Sie 100% statt 99% betrachten.

IMO ist es am besten, hier Reflection zu verwenden, da Sie sonst entweder ein besseres Code-Coverage-Tool benötigen würden, das diese Konstruktoren ignoriert, oder das Code-Coverage-Tool anweisen müssten, die Methode (möglicherweise eine Anmerkung oder eine Konfigurationsdatei) zu ignorieren, da Sie dann stecken bleiben würden mit einem bestimmten Code-Coverage-Tool.

In einer perfekten Welt würden alle Tools zur Codeabdeckung private Konstruktoren ignorieren, die zu einer endgültigen Klasse gehören, da der Konstruktor als "Sicherheitsmaßnahme" nichts anderes enthält :)
Ich würde diesen Code verwenden:

    @Test
    public void callPrivateConstructorsForCodeCoverage() throws SecurityException, NoSuchMethodException, IllegalArgumentException, InstantiationException, IllegalAccessException, InvocationTargetException
    {
        Class<?>[] classesToConstruct = {Foo.class};
        for(Class<?> clazz : classesToConstruct)
        {
            Constructor<?> constructor = clazz.getDeclaredConstructor();
            constructor.setAccessible(true);
            assertNotNull(constructor.newInstance());
        }
    }
Fügen Sie dem Array dann einfach Klassen hinzu, während Sie fortfahren.

jontejj
quelle
5

Neuere Versionen von Cobertura bieten integrierte Unterstützung für das Ignorieren trivialer Getter / Setter / Konstruktoren:

https://github.com/cobertura/cobertura/wiki/Ant-Task-Reference#ignore-trivial

Trivial ignorieren

Das Ignorieren von Trivial ermöglicht das Ausschließen von Konstruktoren / Methoden, die eine Codezeile enthalten. Einige Beispiele umfassen den Aufruf nur eines Superkonstruktors, Getter / Setter-Methoden usw. Um das triviale Argument zum Ignorieren einzuschließen, fügen Sie Folgendes hinzu:

<cobertura-instrument ignoreTrivial="true" />

oder in einem Gradle Build:

cobertura {
    coverageIgnoreTrivial = true
}
Mike Buhot
quelle
4

Tu es nicht. Was bringt es, einen leeren Konstruktor zu testen? Da es in cobertura 2.0 eine Option gibt, solche trivialen Fälle (zusammen mit Setzern / Gettern) zu ignorieren, können Sie sie in maven aktivieren, indem Sie dem cobertura maven-Plugin einen Konfigurationsabschnitt hinzufügen:

<configuration>
  <instrumentation>
    <ignoreTrivial>true</ignoreTrivial>                 
  </instrumentation>
</configuration>

Alternativ können Sie Coverage Annotations verwenden : @CoverageIgnore.

Krzysztof Krasoń
quelle
3

Endlich gibt es eine Lösung!

public enum Foo {;
  public static int bar() {
    return 1;
  }
}
kan
quelle
Wie testet das die Klasse, die in der Frage steht? Sie sollten nicht davon ausgehen, dass Sie jede Klasse mit einem privaten Konstruktor in eine Aufzählung verwandeln können oder möchten.
Jon Skeet
@ JonSkeet Ich kann für die betreffende Klasse. Und die meisten Utility-Klassen, die nur eine Reihe statischer Methoden haben. Andernfalls hat eine Klasse mit dem einzigen privaten Konstruktor keinen Sinn.
Kan
1
Eine Klasse mit einem privaten Konstruktor kann aus öffentlichen statischen Methoden instanziiert werden, obwohl es dann natürlich einfach ist, die Abdeckung zu erhalten. Aber im Grunde würde ich jede Klasse bevorzugen, die sich Enum<E>wirklich auf eine Aufzählung erstreckt ... Ich glaube, das zeigt die Absicht besser.
Jon Skeet
4
Wow, ich würde absolut Code bevorzugen, der gegenüber einer ziemlich willkürlichen Zahl Sinn macht. (Abdeckung ist keine Garantie für Qualität, noch ist eine 100% ige Abdeckung in allen Fällen möglich. Ihre Tests sollten Ihren Code bestenfalls leiten - nicht über eine Klippe bizarrer Absichten lenken.)
Jon Skeet
1
@Kan: Das Hinzufügen eines Dummy-Aufrufs zum Konstruktor zum Bluffen des Tools sollte nicht beabsichtigt sein. Jeder, der sich auf eine einzige Metrik stützt, um das Wohl des Projekts zu bestimmen, ist bereits auf dem Weg zur Zerstörung.
Apoorv Khurasia
1

Ich weiß nichts über Cobertura, aber ich verwende Clover und es hat die Möglichkeit, Musterausgleichsausschlüsse hinzuzufügen. Zum Beispiel habe ich Muster, die Apache-Commons-Protokollierungszeilen ausschließen, damit sie nicht in die Abdeckung einbezogen werden.

John Engelman
quelle
1

Eine andere Möglichkeit besteht darin, einen statischen Initialisierer zu erstellen, der dem folgenden Code ähnelt

class YourClass {
  private YourClass() {
  }
  static {
     new YourClass();
  }

  // real ops
}

Auf diese Weise wird der private Konstruktor als getestet betrachtet und der Laufzeitaufwand ist grundsätzlich nicht messbar. Ich mache das, um mit EclEmma eine 100% ige Abdeckung zu erhalten, aber wahrscheinlich funktioniert es für jedes Abdeckungstool. Der Nachteil dieser Lösung ist natürlich, dass Sie Produktionscode (den statischen Initialisierer) nur zu Testzwecken schreiben.

Christian Lewold
quelle
Ich mache das ziemlich oft. Günstig wie günstig, günstig wie schmutzig, aber effektiv.
Pholser
Bei Sonar führt dies tatsächlich dazu, dass die Klasse durch die Codeabdeckung vollständig übersehen wird.
Adam Parkin
1

ClassUnderTest testClass = Whitebox.invokeConstructor (ClassUnderTest.class);

Acpuma
quelle
Dies sollte die richtige Antwort gewesen sein, da sie genau das beantwortet, was gefragt wird.
Chakian
0

Manchmal markiert Cobertura Code, der nicht ausgeführt werden soll, als "nicht abgedeckt", daran ist nichts auszusetzen. Warum geht es Ihnen darum, statt 99%Deckung zu haben?100% ?

Technisch gesehen können Sie diesen Konstruktor zwar immer noch mit Reflexion aufrufen, aber das klingt für mich (in diesem Fall) sehr falsch.

Nikita Rybak
quelle
0

Wenn ich die Absicht Ihrer Frage erraten würde, würde ich sagen:

  1. Sie möchten angemessene Überprüfungen für private Konstruktoren, die tatsächlich arbeiten, und
  2. Sie möchten, dass Clover leere Konstruktoren für util-Klassen ausschließt.

Für 1 ist es offensichtlich, dass die gesamte Initialisierung über Factory-Methoden erfolgen soll. In solchen Fällen sollten Ihre Tests in der Lage sein, die Nebenwirkungen des Konstruktors zu testen. Dies sollte unter die Kategorie der normalen privaten Methodentests fallen. Verkleinern Sie die Methoden so, dass sie nur eine begrenzte Anzahl bestimmter Dinge ausführen (im Idealfall nur eine Sache und eine Sache gut), und testen Sie dann die Methoden, die auf ihnen beruhen.

Zum Beispiel, wenn mein [privat] Konstruktor setzt auf meine Klasse Instanzfelder azu 5. Dann kann (oder muss) ich es testen:

@Test
public void testInit() {
    MyClass myObj = MyClass.newInstance(); //Or whatever factory method you put
    Assert.assertEquals(5, myObj.getA()); //Or if getA() is private then test some other property/method that relies on a being 5
}

Für 2 können Sie clover so konfigurieren, dass Util-Konstruktoren ausgeschlossen werden, wenn Sie ein festgelegtes Namensmuster für Util-Klassen haben. ZB verwende ich in meinem eigenen Projekt so etwas (weil wir der Konvention folgen, dass Namen für alle Util-Klassen mit Util enden sollten):

<clover-setup initString="${build.dir}/clovercoverage.db" enabled="${with.clover}">
    <methodContext name="prvtCtor" regexp="^private *[a-zA-Z0-9_$]+Util *( *) *"/>
</clover-setup>

Ich habe bewusst eine .*Gefolgschaft ausgelassen) weil solche Konstruktoren keine Ausnahmen auslösen sollen (sie sollen nichts tun).

Es kann natürlich einen dritten Fall geben, in dem Sie möglicherweise einen leeren Konstruktor für eine Nicht-Utility-Klasse haben möchten. In solchen Fällen würde ich empfehlen, dass Sie eine methodContextmit der genauen Signatur des Konstruktors eingeben.

<clover-setup initString="${build.dir}/clovercoverage.db" enabled="${with.clover}">
    <methodContext name="prvtCtor" regexp="^private *[a-zA-Z0-9_$]+Util *( *) *"/>
    <methodContext name="myExceptionalClassCtor" regexp="^private MyExceptionalClass()$"/>
</clover-setup>

Wenn Sie viele solcher außergewöhnlichen Klassen haben, können Sie den von mir vorgeschlagenen verallgemeinerten privaten Konstruktor reg-ex ändern und daraus entfernen Util. In diesem Fall müssen Sie manuell sicherstellen, dass die Nebenwirkungen Ihres Konstruktors weiterhin getestet und von anderen Methoden in Ihrer Klasse / Ihrem Projekt abgedeckt werden.

<clover-setup initString="${build.dir}/clovercoverage.db" enabled="${with.clover}">
    <methodContext name="prvtCtor" regexp="^private *[a-zA-Z0-9_$]+ *( *) .*"/>
</clover-setup>
Apoorv Khurasia
quelle
0
@Test
public void testTestPrivateConstructor() {
    Constructor<Test> cnt;
    try {
        cnt = Test.class.getDeclaredConstructor();
        cnt.setAccessible(true);

        cnt.newInstance();
    } catch (Exception e) {
        e.getMessage();
    }
}

Test.java ist Ihre Quelldatei mit Ihrem privaten Konstruktor

DPREDDY
quelle
Es wäre schön zu erklären, warum dieses Konstrukt bei der Abdeckung hilft.
Markus
Richtig und zweitens: Warum in Ihrem Test eine Ausnahme abfangen? Die ausgelöste Ausnahme sollte den Test tatsächlich zum Scheitern bringen.
Jordi
0

Das Folgende hat mir bei einer Klasse geholfen, die mit der Lombok-Annotation @UtilityClass erstellt wurde und automatisch einen privaten Konstruktor hinzufügt.

@Test
public void testConstructorIsPrivate() throws IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchMethodException {
    Constructor<YOUR_CLASS_NAME> constructor = YOUR_CLASS_NAME.class.getDeclaredConstructor();
    assertTrue(Modifier.isPrivate(constructor.getModifiers())); //this tests that the constructor is private
    constructor.setAccessible(true);
    assertThrows(InvocationTargetException.class, () -> {
        constructor.newInstance();
    }); //this add the full coverage on private constructor
}

Obwohl constructor.setAccessible (true) funktionieren sollte, wenn der private Konstruktor manuell geschrieben wurde, funktioniert die Lombok-Annotation nicht, da sie erzwungen wird. Constructor.newInstance () testet tatsächlich, ob der Konstruktor aufgerufen wird, und vervollständigt damit die Abdeckung des Costructors selbst. Mit assertThrows verhindern Sie, dass der Test fehlschlägt, und Sie haben die Ausnahme verwaltet, da genau der Fehler vorliegt, den Sie erwarten. Obwohl dies eine Problemumgehung ist und ich das Konzept der "Leitungsabdeckung" gegenüber der "Funktions- / Verhaltensabdeckung" nicht schätze, können wir bei diesem Test einen Sinn finden. Tatsächlich sind Sie sicher, dass die Utility-Klasse tatsächlich einen privaten Konstruktor hat, der eine Ausnahme korrekt auslöst, wenn er auch über eine Reflaktion aufgerufen wird. Hoffe das hilft.

Riccardo Solimena
quelle
Hallo @ShanteshwarInde. Vielen Dank. Meine Eingabe wurde gemäß Ihren Vorschlägen bearbeitet und vervollständigt. Grüße.
Riccardo Solimena
0

Meine bevorzugte Option im Jahr 2019: Verwenden Sie Lombok.

Insbesondere die @UtilityClassAnmerkung . (Zum Zeitpunkt des Schreibens leider nur "experimentell", aber es funktioniert einwandfrei und hat einen positiven Ausblick, sodass es wahrscheinlich bald auf stabil aktualisiert wird.)

Diese Annotation fügt den privaten Konstruktor hinzu, um eine Instanziierung zu verhindern, und macht die Klasse endgültig. In Kombination mit lombok.addLombokGeneratedAnnotation = truein lombok.configignorieren so gut wie alle Test-Frameworks den automatisch generierten Code bei der Berechnung der Testabdeckung, sodass Sie die Abdeckung dieses automatisch generierten Codes ohne Hacks oder Reflexionen umgehen können.

Michael Berry
quelle
-2

Das kannst du nicht.

Sie erstellen anscheinend den privaten Konstruktor, um die Instanziierung einer Klasse zu verhindern, die nur statische Methoden enthalten soll. Anstatt zu versuchen, die Abdeckung dieses Konstruktors zu erhalten (was die Instanziierung der Klasse erfordern würde), sollten Sie ihn entfernen und Ihren Entwicklern vertrauen, dass sie der Klasse keine Instanzmethoden hinzufügen.

Anon
quelle
3
Das ist falsch; Sie können es wie oben erwähnt durch Reflexion instanziieren.
Theotherian
Das ist schlecht. Lassen Sie niemals den öffentlichen Standardkonstruktor anzeigen. Fügen Sie den privaten hinzu, um zu verhindern, dass er aufgerufen wird.
Lho Ben