Можно ли протестировать закрытый конструктор с нулевым параметром, если один из аргументов конструктора имеет тип List?

Я использую jMockit для модульного тестирования некоторых новых объектов. В моем конкретном случае я пытаюсь проверить реакцию частного конструктора на нулевой параметр. Рассмотрим пример:

public abstract class Foo {

    private final String nickname;

    public Foo(final String nickname) {
        // Check condition
        Preconditions.checkNotNull(nickname);
        // Do some stuff
        int i=0; while (i<10) {i++; System.out.println("I can count to "+i);} 
        // Store value
        this.nickname = nickname;
    }

    public boolean isItMyName(String alias) {
        return (nickname.equalsIgnoreCase(alias));
    }

}

с

public class Bar extends Foo {

    private final String professionalNickname;
    private final List<String> jailhouseNicknames = new ArrayList<String>();

    private Bar(final String casualNickname, 
            final String professionalNickname,
            final List<String> jailhouseNicknames) {
        super(casualNickname);
        Preconditions.checkNotNull(professionalNickname);
        Preconditions.checkNotNull(jailhouseNicknames);
        this.professionalNickname = professionalNickname;
        this.jailhouseNicknames.addAll(jailhouseNicknames);
    }

    @Override
    public boolean isItMyName(String alias) {
        if (super.isItMyName(alias)) return true;
        if (professionalNickname.equalsIgnoreCase(alias)) return true;
        for (String nick : jailhouseNicknames)
            if (nick.equalsIgnoreCase(alias)) return true;
        return false;
    }

}

Если я хочу протестировать конструктор Bar с помощью jMockit, я могу использовать Deencapsulation.newInstance(Class classToInstantiate, Object... nonNullArgs). Однако в моем случае я хочу, чтобы один из параметров (в частности, одна из строк) был нулевой ссылкой. В этом случае я должен использовать метод Deencapsulation.newInstance(Class classToInstantiate, Class[] parameterTypes, Object... initArgs). Это потребует от меня пройти в Class‹ List‹ String > >, но в соответствии с этот прошлый ответ, это плохая практика и возможна только путем приведения типов.

Даже если я отброшу осторожность на ветер и попытаюсь сделать что-то вроде

Class<List<String>> listClass = ((Class<List<String>>)new ArrayList<String>().getClass());
Deencapsulation.newInstance(
            Bar.class, 
            new Class<?>[] {String.class, String.class, listClass},
            someString, 
            null, 
            someListOfStrings);

я получаю ошибку

Вызвано: java.lang.IllegalArgumentException: указанный конструктор не найден: DiscreteSlot(java.lang.String, java.lang.String, java.util.ArrayList)

Есть ли способ сделать то, что я пытаюсь?


person skippy    schedule 02.06.2016    source источник
comment
Параметр просто типа List.class; все это приведение listClass ни к чему не приведет: вы на самом деле передаете ArrayList.class, и нет перегрузки конструктора, которая принимает ArrayList.   -  person Andy Turner    schedule 02.06.2016
comment
@AndyTurner, ты прав, я терплю неудачу. Это решило мою проблему.   -  person skippy    schedule 02.06.2016
comment
Если вы являетесь владельцем тестируемого кода, я предлагаю сделать конструктор закрытым для пакета и поместить ваш тест в тот же пакет (в другом исходном дереве).   -  person NamshubWriter    schedule 11.06.2016


Ответы (2)


Конструктор, который вы пытаетесь вызвать, принимает List в качестве третьего параметра, поэтому вы должны передать List.class в качестве третьего класса в массиве, чтобы вызывать его рефлексивно.

Однако вы передаете результат этого выражения:

((Class<List<String>>)new ArrayList<String>().getClass());

что равно

ArrayList.class

Поскольку нет конструктора, который принимает ArrayList, он говорит, что конструктор не найден.

Вместо этого передайте List.class.

person Andy Turner    schedule 02.06.2016

Тип параметра конструктора — List, а не ArrayList. Просто сделайте это:

Deencapsulation.newInstance(
        Bar.class, 
        new Class<?>[] {String.class, String.class, List.class}, // use List class literal
        someString, 
        null, 
        someListOfStrings);

Выражение new ArrayList<String>().getClass() возвращает ArrayList.class, которое не равно List.class.

person Bohemian♦    schedule 02.06.2016