46

クラスに多数の静的メソッドが含まれている場合、誰もこのクラスのインスタンスを誤って初期化しないようにするために、プライベート コンストラクターを作成しました。

private Utils() {
}

さて..コンストラクターが見えない場合、これをどのようにテストできますか? これはテストでカバーできますか?

4

7 に答える 7

73

リフレクションを使用すると、プライベートコンストラクターを呼び出すことができます。

Constructor<Util> c = Utils.class.getDeclaredConstructor();
c.setAccessible(true);
Utils u = c.newInstance(); // Hello sailor

ただし、それでも不可能にすることができます。

private Utils() {
    throw new UnsupportedOperationException();
}

コンストラクターで例外をスローすることにより、すべての試行を防ぎます。


私もクラス自体を作成しfinalます。「理由」:

public final class Utils {
    private Utils() {
        throw new UnsupportedOperationException();
    }
}
于 2012-12-29T01:25:40.033 に答える
22

コードの意図をテストしてください..常に:)

例: コンストラクターが非公開であることのポイントが見られない場合、テストする必要があるのはこの事実であり、他には何もありません。

リフレクションAPIを使用してコンストラクターを照会し、プライベート属性が設定されていることを検証します。

私はこのようなことをします:

@Test()
public void testPrivateConstructors() {
    final Constructor<?>[] constructors = Utils.class.getDeclaredConstructors();
    for (Constructor<?> constructor : constructors) {
        assertTrue(Modifier.isPrivate(constructor.getModifiers()));
    }
}

オブジェクトの構築を適切にテストしたい場合は、構築されたオブジェクトを取得できるパブリック API をテストする必要があります。それが、前述の API が存在する必要がある理由です。オブジェクトを適切に構築するため、そのためにテストする必要があります :)。

于 2012-12-29T01:29:45.497 に答える
6
@Test
public//
void privateConstructorTest() throws Exception {
    final Constructor<?>[] constructors = Utils.class.getDeclaredConstructors();
    // check that all constructors are 'private':
    for (final Constructor<?> constructor : constructors) {
        Assert.assertTrue(Modifier.isPrivate(constructor.getModifiers()));
    }        
    // call the private constructor:
    constructors[0].setAccessible(true);
    constructors[0].newInstance((Object[]) null);
}
于 2012-12-29T01:23:40.170 に答える
5

誰もこのクラスのインスタンスを誤って初期化しないようにするため

通常、私が行うことは、メソッド/コンストラクターをプライベートからデフォルトのパッケージの可視性に変更することです。また、テストクラスに同じパッケージを使用しているため、外部からではなくても、テストからメソッド/コンストラクターにアクセスできます。

クラスをインスタンス化しないようにポリシーを適用するには、次のことができます。

  1. デフォルトの空のコンストラクターから UnsupportedOperationException("このクラスをインスタンス化しないでください!") をスローします。
  2. クラス抽象を宣言します。静的メソッドのみが含まれている場合、静的メソッドを呼び出すことはできますが、サブクラス化しない限り、インスタンス化することはできません。

テストがターゲット クラスと同じパッケージを共有している場合は、コンストラクターをサブクラス化して実行できます。これはかなり「エラープルーフ」である必要があります。悪意のあるコーダーは常に回避策を見つけます:)

于 2012-12-29T01:46:46.717 に答える
4

プライベート コンストラクターがある場合は、コードのプライベートではないメソッドから呼び出されます。したがって、そのメソッドをテストすると、コンストラクターがカバーされます。メソッドごとにテストを行うことに宗教的な美徳はありません。関数またはブランチ カバレッジ レベルを探している場合、コンストラクターを使用するコード パスを介してコンストラクターを実行するだけで、それを取得できます。

そのコード パスが複雑でテストが難しい場合は、リファクタリングが必要になる可能性があります。

于 2012-12-29T01:34:21.430 に答える
3

次のようなコンストラクターに例外を追加する場合:

private Utils() {
    throw new UnsupportedOperationException();
}

constructor.newInstance()テスト クラスで を呼び出すと、InvocationTargetException代わりに がスローされますUnsupportedOperationExceptionが、必要な例外はスローされた例外に含まれます。
例外のスローをアサートしたい場合は、呼び出し例外がキャッチされると、呼び出し例外のターゲットをスローできます
たとえば、jUnit 4 を使用すると、次のことができます。

@Test(expected = UnsupportedOperationException.class)
public void utilityClassTest() throws NoSuchMethodException, IllegalAccessException, InstantiationException {
    final Constructor<Utils> constructor = Utils.class.getDeclaredConstructor();
    constructor.setAccessible(true);
    try {
        constructor.newInstance();
    } catch (InvocationTargetException e) {
        throw (UnsupportedOperationException) e.getTargetException();
    }
}
于 2015-08-11T09:39:41.927 に答える