Làm cách nào để thêm phạm vi kiểm tra vào một phương thức khởi tạo riêng?


110

Đây là mã:

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

Đây là bài kiểm tra:

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
  }
}

Hoạt động tốt, lớp đã được kiểm tra. Nhưng Cobertura nói rằng không có vùng phủ mã nào của phương thức khởi tạo riêng của lớp. Làm thế nào chúng ta có thể thêm phạm vi kiểm tra vào một phương thức khởi tạo riêng như vậy?


Đối với tôi, dường như bạn đang cố gắng thực thi mô hình Singleton. Nếu vậy, bạn có thể muốn dp4j.com (mà thực hiện chính xác đó)
simpatico

không nên thay thế "cố ý làm trống" bằng ngoại lệ ném? Trong trường hợp đó, bạn có thể viết thử nghiệm mong đợi rằng ngoại lệ cụ thể với thông báo cụ thể, không? không chắc chắn nếu điều này là quá mức cần thiết
Ewoks

Câu trả lời:


85

Chà, có nhiều cách bạn có thể sử dụng phản chiếu, v.v. - nhưng nó có thực sự đáng giá không? Đây là một hàm tạo không bao giờ được gọi , phải không?

Nếu có một chú thích hoặc bất cứ điều gì tương tự mà bạn có thể thêm vào lớp để làm cho Cobertura hiểu rằng nó sẽ không được gọi, hãy làm điều đó: Tôi không nghĩ rằng việc thêm phạm vi phủ sóng một cách giả tạo là không đáng.

CHỈNH SỬA: Nếu không có cách nào làm điều đó, chỉ cần sống với phạm vi phủ sóng giảm nhẹ. Hãy nhớ rằng phạm vi bảo hiểm có nghĩa là một cái gì đó hữu ích cho bạn - bạn nên phụ trách công cụ này, chứ không phải ngược lại.


18
Tôi không muốn "hơi giảm vùng phủ sóng" trong toàn bộ dự án chỉ vì nhà xây dựng đặc biệt này ..
yegor256

36
@Vincenzo: Thì IMO bạn đang đặt giá trị quá cao cho một số đơn giản. Mức độ bao phủ là một chỉ số của thử nghiệm. Đừng làm nô lệ cho một công cụ. Mục đích của phạm vi bảo hiểm là cung cấp cho bạn mức độ tin cậy và đề xuất các khu vực để thử nghiệm thêm. Việc gọi một cách giả tạo một phương thức khởi tạo không sử dụng khác không giúp được gì cho một trong hai điểm đó.
Jon Skeet

19
@JonSkeet: Tôi hoàn toàn đồng ý với "Đừng làm nô lệ cho một công cụ", nhưng việc nhớ mọi "số lượng sai sót" trong mọi dự án không có gì hay ho. Làm thế nào để đảm bảo kết quả 7/9 là giới hạn của Cobertura, và không phải của lập trình viên? Một lập trình viên mới phải nhập mọi lỗi (có thể gặp nhiều trong các dự án lớn) để kiểm tra từng lớp.
Eduardo Costa

5
Điều này không trả lời câu hỏi. và nhân tiện, một số nhà quản lý xem xét các con số phủ sóng. Họ không quan tâm tại sao. Họ biết rằng 85% tốt hơn 75%.
ACV

2
Một trường hợp sử dụng thực tế để kiểm tra mã không thể truy cập khác là đạt được phạm vi kiểm tra 100% để không ai phải xem lại lớp đó. Nếu phạm vi phủ sóng bị kẹt ở mức 95%, nhiều nhà phát triển có thể cố gắng tìm ra lý do cho điều đó chỉ để lặp đi lặp lại vấn đề này.
thisismydesign

140

Tôi không hoàn toàn đồng ý với Jon Skeet. Tôi nghĩ rằng nếu bạn có thể giành được một chiến thắng dễ dàng để cung cấp cho bạn phạm vi bảo hiểm và loại bỏ nhiễu trong báo cáo mức độ phù hợp của bạn, thì bạn nên làm điều đó. Hoặc yêu cầu công cụ bao phủ của bạn bỏ qua hàm tạo, hoặc gạt chủ nghĩa lý tưởng sang một bên và viết bài kiểm tra sau và thực hiện với nó:

@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();
}

25
Nhưng điều này đang loại bỏ nhiễu trong báo cáo phạm vi bằng cách thêm nhiễu vào bộ thử nghiệm. Tôi sẽ chỉ kết thúc câu ở "gạt chủ nghĩa lý tưởng sang một bên". :)
Christopher Orr

11
Để cung cấp cho bài kiểm tra này bất kỳ loại ý nghĩa nào, bạn có thể cũng nên khẳng định rằng cấp độ truy cập của phương thức khởi tạo là những gì bạn mong đợi.
Jeremy

Thêm phản ánh xấu xa cộng với ý tưởng của Jeremy cộng với một cái tên có ý nghĩa như "testIfConstructorIsPrivateWithoutRaisingExceptions", tôi đoán đây là câu trả lời "THE".
Eduardo Costa

1
Điều này là không chính xác về mặt cú pháp phải không? Là constructorgì? Không nên Constructorđược tham số hóa và không phải là một kiểu thô?
Adam Parkin

2
Điều này là sai: constructor.isAccessible()luôn trả về false, ngay cả trên một phương thức khởi tạo công khai. Một người nên sử dụng assertTrue(Modifier.isPrivate(constructor.getModifiers()));.
timomeinen

78

Mặc dù nó không nhất thiết phải dành cho phạm vi bảo hiểm, nhưng tôi đã tạo phương thức này để xác minh rằng lớp tiện ích được xác định rõ và cũng thực hiện một chút phạm vi bảo hiểm.

/**
 * 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);
        }
    }
}

Tôi đã đặt mã đầy đủ và ví dụ trong https://github.com/trajano/maven-jee6/tree/master/maven-jee6-test


11
+1 Điều này không chỉ giải quyết vấn đề mà không cần lừa công cụ mà còn kiểm tra đầy đủ các tiêu chuẩn mã hóa của việc thiết lập một lớp tiện ích. Tôi đã phải thay đổi kiểm tra khả năng truy cập để sử dụng Modifier.isPrivatenhư isAccessibleđược trả lại truecho các hàm tạo riêng trong một số trường hợp (chế nhạo sự can thiệp của thư viện?).
David Harkness

4
Tôi thực sự muốn thêm điều này vào lớp Assert của JUnit, nhưng không muốn nhận công lao cho công việc của bạn. Tôi nghĩ nó rất tốt. Sẽ thật tuyệt nếu có Assert.utilityClassWellDefined()trong JUnit 4.12+. Bạn đã xem xét một yêu cầu kéo chưa?
Visionary Software Solutions

Lưu ý rằng việc sử dụng setAccessible()để làm cho phương thức khởi tạo có thể truy cập được sẽ gây ra sự cố cho công cụ bao phủ mã của Sonar (khi tôi làm điều này, lớp này sẽ biến mất khỏi báo cáo phạm vi mã của Sonar).
Adam Parkin

Cảm ơn, tôi đã đặt lại cờ có thể truy cập được. Có lẽ đó là một lỗi trên chính Sonar?
Archimedes Trajano

Tôi đã xem báo cáo Sonar để biết mức độ phù hợp trên plugin batik maven của mình, có vẻ như nó đã bao phủ chính xác. site.trajano.net/batik-maven-plugin/cobertura/index.html
Archimedes Trajano

19

Tôi đã đặt private là phương thức khởi tạo của lớp hàm tiện ích tĩnh của tôi, để đáp ứng CheckStyle. Nhưng giống như tấm áp phích gốc, tôi đã yêu cầu Cobertura phàn nàn về bài kiểm tra. Lúc đầu, tôi đã thử cách tiếp cận này, nhưng điều này không ảnh hưởng đến báo cáo phạm vi bởi vì hàm tạo không bao giờ thực sự được thực thi. Vì vậy, thực sự tất cả các thử nghiệm này là nếu phương thức khởi tạo vẫn còn riêng tư - và điều này được thực hiện dư thừa bởi kiểm tra khả năng tiếp cận trong thử nghiệm tiếp theo.

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

Tôi đã theo gợi ý của Javid Jamae và sử dụng phản xạ, nhưng thêm các xác nhận để bắt bất kỳ ai gây rối với lớp đang được kiểm tra (và đặt tên cho bài kiểm tra để chỉ Mức độ Ác cao).

@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());
}

Điều này là quá mức cần thiết, nhưng tôi phải thừa nhận rằng tôi thích cảm giác mờ ảo ấm áp của phương pháp bao phủ 100%.


Overkill nó có thể được, nhưng nếu nó được trong Unitils hoặc tương tự, tôi muốn sử dụng nó
Stewart

+1 Khởi đầu tốt, mặc dù tôi đã làm với bài kiểm tra hoàn chỉnh hơn của Archimedes .
David Harkness

Ví dụ đầu tiên không hoạt động - IllegalAccesException có nghĩa là phương thức khởi tạo không bao giờ được gọi, vì vậy phạm vi bảo hiểm không được ghi lại.
Tom McIntyre

IMO, giải pháp trong đoạn mã đầu tiên là giải pháp sạch nhất và đơn giản nhất trong cuộc thảo luận này. Chỉ cần dòng với fail(...)là không cần thiết.
Piotr Wittchen

9

Với Java 8 , có thể tìm ra giải pháp khác.

Tôi giả sử rằng bạn chỉ muốn tạo một lớp tiện ích với một vài phương thức tĩnh công khai. Nếu bạn có thể sử dụng Java 8, thì bạn có thể sử dụng interfacethay thế.

package com.XXX;

public interface Foo {

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

Không có nhà xây dựng và không có phàn nàn từ Cobertura. Bây giờ bạn chỉ cần kiểm tra những dòng bạn thực sự quan tâm.


1
Tuy nhiên, thật không may, bạn không thể khai báo giao diện là "cuối cùng", ngăn không cho bất kỳ ai phân lớp nó - nếu không đây sẽ là cách tiếp cận tốt nhất.
Michael Berry

5

Lý do đằng sau việc kiểm tra mã không làm được gì là để đạt được độ phủ mã 100% và để ý khi độ phủ mã giảm xuống. Nếu không, người ta luôn có thể nghĩ, này, tôi không có phạm vi bảo hiểm mã 100% nữa nhưng nó RẤT HẤP DẪN vì các hàm tạo riêng của tôi. Điều này giúp bạn dễ dàng phát hiện các phương thức chưa được kiểm tra mà không cần phải kiểm tra xem nó có phải là một phương thức khởi tạo riêng hay không. Khi cơ sở mã của bạn phát triển, bạn sẽ thực sự cảm thấy một cảm giác ấm áp dễ chịu khi nhìn vào 100% thay vì 99%.

IMO tốt nhất nên sử dụng phản chiếu ở đây vì nếu không bạn sẽ phải có một công cụ bao phủ mã tốt hơn để bỏ qua các hàm tạo này hoặc bằng cách nào đó yêu cầu công cụ bao phủ mã bỏ qua phương thức (có thể là Chú thích hoặc tệp cấu hình) vì khi đó bạn sẽ bị mắc kẹt với một công cụ bao phủ mã cụ thể.

Trong một thế giới hoàn hảo, tất cả các công cụ bao phủ mã sẽ bỏ qua các hàm tạo riêng thuộc về lớp cuối cùng vì hàm tạo ở đó như một biện pháp "bảo mật" không có gì khác :)
Tôi sẽ sử dụng mã này:

    @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());
        }
    }
Và sau đó chỉ cần thêm các lớp vào mảng khi bạn tiếp tục.


5

Các phiên bản mới hơn của Cobertura có hỗ trợ tích hợp để bỏ qua getters / setters / constructors tầm thường:

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

Bỏ qua tầm thường

Bỏ qua tầm thường cho phép khả năng loại trừ các hàm tạo / phương thức chứa một dòng mã. Một số ví dụ bao gồm lệnh gọi chỉ một trình tạo siêu, các phương thức getter / setter, v.v. Để bao gồm đối số tầm thường bỏ qua, hãy thêm phần sau:

<cobertura-instrument ignoreTrivial="true" />

hoặc trong bản dựng Gradle:

cobertura {
    coverageIgnoreTrivial = true
}

4

Đừng. Điểm mấu chốt trong việc kiểm tra một hàm tạo rỗng là gì? Vì cobertura 2.0 có một tùy chọn để bỏ qua những trường hợp nhỏ nhặt như vậy (cùng với setters / getters), bạn có thể bật nó trong maven bằng cách thêm phần cấu hình vào plugin cobertura maven:

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

Hoặc bạn có thể sử dụng Bảo hiểm Chú thích : @CoverageIgnore.


3

Cuối cùng, có giải pháp!

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

Làm thế nào để kiểm tra lớp được đăng trong câu hỏi? Bạn không nên cho rằng bạn có thể biến mọi lớp với một phương thức khởi tạo riêng thành một enum hoặc mà bạn muốn.
Jon Skeet

@JonSkeet Tôi có thể cho lớp học được đề cập. Và hầu hết các lớp tiện ích chỉ có một loạt các phương thức tĩnh. Nếu không thì một lớp có hàm tạo riêng duy nhất không có ý nghĩa gì.
kan

1
Một lớp với một phương thức khởi tạo riêng có thể được khởi tạo từ các phương thức tĩnh công cộng, mặc dù tất nhiên sau đó rất dễ để có được vùng phủ sóng. Nhưng về cơ bản, tôi muốn bất kỳ lớp nào mở rộng Enum<E>thực sự là một enum ... Tôi tin rằng điều đó tiết lộ ý định tốt hơn.
Jon Skeet

4
Chà, tôi hoàn toàn thích mã có ý nghĩa hơn là một con số khá tùy ý. (Bảo hiểm không đảm bảo chất lượng, cũng không phải là% độ bao phủ 100 có tính khả thi trong tất cả các trường hợp thử nghiệm của bạn nên. Hướng dẫn mã của bạn lúc tốt nhất -. Không chỉ đạo nó trên một vách đá của ý định kỳ lạ)
Jon Skeet

1
@Kan: Thêm một lệnh gọi giả vào hàm tạo để đánh lừa công cụ không phải là mục đích. Bất kỳ ai dựa vào một số liệu duy nhất để xác định mức độ an toàn của dự án đều đang trên con đường dẫn đến sự hủy diệt.
Apoorv Khurasia

1

Tôi không biết về Cobertura nhưng tôi sử dụng Clover và nó có một phương tiện để thêm các loại trừ phù hợp với mẫu. Ví dụ: tôi có các mẫu loại trừ các dòng ghi nhật ký apache-commons để chúng không được tính trong phạm vi bảo hiểm.


1

Một tùy chọn khác là tạo bộ khởi tạo tĩnh tương tự như đoạn mã sau

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

  // real ops
}

Bằng cách này, phương thức khởi tạo riêng được coi là đã được kiểm tra và chi phí thời gian chạy về cơ bản là không thể đo lường được. Tôi làm điều này để có được độ che phủ 100% bằng cách sử dụng EclEmma, ​​nhưng có khả năng nó hoạt động cho mọi công cụ che phủ. Tất nhiên, hạn chế của giải pháp này là bạn viết mã sản xuất (trình khởi tạo tĩnh) chỉ cho mục đích thử nghiệm.


Tôi làm điều này khá một chút. Rẻ như ở không đắt, rẻ như ở bẩn, nhưng hiệu quả.
pholser

Với Sonar, điều này thực sự khiến lớp bị bỏ sót hoàn toàn bởi vùng phủ mã.
Adam Parkin

1

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


Đây đáng lẽ phải là câu trả lời chính xác vì nó trả lời chính xác những gì được hỏi.
Chakian

0

Đôi khi Cobertura đánh dấu mã không dự định được thực thi là 'không được bảo vệ', không có gì sai với điều đó. Tại sao bạn quan tâm đến việc có 99%bảo hiểm thay vì100% ?

Mặc dù vậy, về mặt kỹ thuật, bạn vẫn có thể gọi phương thức khởi tạo đó với sự phản chiếu, nhưng tôi nghe có vẻ rất sai (trong trường hợp này).


0

Nếu tôi đoán được mục đích câu hỏi của bạn, tôi sẽ nói:

  1. Bạn muốn kiểm tra hợp lý đối với các trình tạo riêng hoạt động thực tế và
  2. Bạn muốn cỏ ba lá loại trừ các hàm tạo trống cho các lớp sử dụng.

Đối với 1, rõ ràng là bạn muốn tất cả khởi tạo được thực hiện thông qua các phương thức gốc. Trong những trường hợp như vậy, các bài kiểm tra của bạn sẽ có thể kiểm tra các tác dụng phụ của hàm tạo. Điều này sẽ thuộc loại thử nghiệm phương pháp tư nhân thông thường. Làm cho các phương pháp nhỏ hơn để chúng chỉ làm một số việc xác định hạn chế (lý tưởng là chỉ một việc và một việc tốt) và sau đó kiểm tra các phương pháp dựa vào chúng.

Ví dụ: nếu phương thức khởi tạo [private] của tôi thiết lập các trường cá thể của lớp tôi athành 5. Sau đó, tôi có thể (hoặc đúng hơn là phải) kiểm tra nó:

@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
}

Đối với 2, bạn có thể định cấu hình cỏ ba lá để loại trừ các hàm tạo Util nếu bạn có một mẫu đặt tên cho các lớp Util. Ví dụ: trong dự án của riêng tôi, tôi sử dụng một cái gì đó như thế này (vì chúng tôi tuân theo quy ước rằng tên cho tất cả các lớp Util phải kết thúc bằng Util):

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

Tôi đã cố tình bỏ qua một phần .*sau) bởi vì các hàm tạo như vậy không có nghĩa là để ném các ngoại lệ (chúng không có nghĩa là để làm bất cứ điều gì).

Tất nhiên có thể có trường hợp thứ ba mà bạn có thể muốn có một phương thức khởi tạo trống cho một lớp không phải tiện ích. Trong những trường hợp như vậy, tôi khuyên bạn nên đặt một methodContextvới chữ ký chính xác của hàm tạo.

<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>

Nếu bạn có nhiều lớp đặc biệt như vậy thì bạn có thể chọn sửa đổi phương thức khởi tạo riêng tổng quát reg-ex mà tôi đã đề xuất và xóa Utilkhỏi nó. Trong trường hợp này, bạn sẽ phải tự đảm bảo rằng các tác dụng phụ của phương thức khởi tạo vẫn được kiểm tra và bao phủ bởi các phương thức khác trong lớp / dự án của bạn.

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

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 là tệp nguồn của bạn, có hàm tạo riêng của bạn


Thật tuyệt khi giải thích, tại sao cấu trúc này lại giúp bảo hiểm.
Markus,

Đúng, và thứ hai: tại sao lại bắt một ngoại lệ trong thử nghiệm của bạn? Ngoại lệ được ném thực sự sẽ làm cho thử nghiệm thất bại.
Jordi

0

Phần sau đã làm việc với tôi trên một lớp được tạo bằng Lombok annotation @UtilityClass, lớp này tự động thêm một phương thức khởi tạo riêng.

@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
}

Mặc dù constructor.setAccessible (true) sẽ hoạt động khi phương thức khởi tạo riêng được viết theo cách thủ công, với chú thích Lombok không hoạt động, vì nó bắt buộc. Constructor.newInstance () thực sự kiểm tra xem phương thức khởi tạo có được gọi hay không và điều này hoàn thành phạm vi bảo hiểm của chính trình cấu trúc chi phí. Với khẳng định, bạn ngăn chặn việc kiểm tra không thành công và bạn đã quản lý ngoại lệ vì đó chính xác là lỗi mà bạn mong đợi. Mặc dù đây là một cách giải quyết và tôi không đánh giá cao khái niệm "phạm vi đường truyền" so với "phạm vi chức năng / hành vi", chúng tôi có thể tìm thấy ý nghĩa trong thử nghiệm này. Trên thực tế, bạn chắc chắn rằng Lớp tiện ích thực sự có một Constructor riêng tư ném chính xác một ngoại lệ khi được gọi cũng thông qua phản ứng lại. Hi vọng điêu nay co ich.


Xin chào @ShanteshwarInde. Cảm ơn rất nhiều. Đầu vào của tôi đã được chỉnh sửa và hoàn thành theo đề xuất của bạn. Trân trọng.
Riccardo Solimena

0

Lựa chọn ưa thích của tôi trong năm 2019: Sử dụng lombok.

Cụ thể, @UtilityClasschú thích . (Đáng buồn là nó chỉ là "thử nghiệm" tại thời điểm viết bài, nhưng nó hoạt động tốt và có triển vọng tích cực, vì vậy có khả năng sớm được nâng cấp lên ổn định.)

Chú thích này sẽ thêm phương thức khởi tạo riêng để ngăn việc khởi tạo và sẽ làm cho lớp cuối cùng. Khi được kết hợp với lombok.addLombokGeneratedAnnotation = truein lombok.config, hầu hết các khuôn khổ thử nghiệm sẽ bỏ qua mã được tạo tự động khi tính toán phạm vi kiểm tra, cho phép bạn bỏ qua phạm vi của mã được tạo tự động đó mà không bị hack hoặc phản ánh.


-2

Bạn không thể.

Rõ ràng bạn đang tạo phương thức khởi tạo riêng để ngăn chặn việc khởi tạo một lớp chỉ chứa các phương thức tĩnh. Thay vì cố gắng tìm hiểu về hàm tạo này (sẽ yêu cầu lớp phải được khởi tạo), bạn nên loại bỏ nó và tin tưởng các nhà phát triển của bạn không thêm các phương thức cá thể vào lớp.


3
Điều đó không chính xác; bạn có thể khởi tạo nó thông qua phản chiếu, như đã nói ở trên.
theotherian

Thật tệ, đừng bao giờ để hàm tạo public mặc định hiển thị, bạn nên thêm private để ngăn việc gọi nó.
Lho Ben
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.