JMockit - Ожидания - соответствующий вызов метода, который включает фиктивный объект в качестве аргумента

Я использую JMockit для тестирования приложения (Java 8, Junit 4.12, JMockit 1.17).

У меня есть код, который должен загружать данные в список конечных точек.

Класс, который фактически выполняет загрузку в конечную точку, называется PlatformDataUploader. У этого класса есть метод, называемый «выгрузка», который выполняет одиночную «загрузку» в единственную конечную точку. Этот метод принимает имя места назначения (которое представляет собой двухсимвольную строку и загружаемый объект). На основе имени места назначения он формирует URL-адрес, по которому должны быть отправлены данные.

Я хотел бы создать тест, который просто подтверждает, что при выполнении приложения метод загрузки PlatformDataUploader вызывается ожидаемое количество раз (7 раз, поскольку приложение в настоящее время настроено для загрузки данных на 7 конечных точек). Я хотел бы подтвердить, что строка назначения, которая передается методу загрузки, является ожидаемой, но меня не интересуют отправляемые данные (представленные экземпляром PlatformInstallationData).

Упрощенная версия кода приложения выглядит следующим образом:

 ...

 private boolean uploadToServices(final List<String> serviceNames) {

    boolean allGood = true;

    PlatformDataUploader platformDataUploader = new PlatformDataUploader();

    for (String serviceName : serviceNames) {

        LOG.info("Attempting to upload to " + serviceName + "...");

        // construct object to send
        PlatformInstallationData platformInstallationData = new PlatformInstallationData();

        ...
        // code here that adds content to platformInstallationData
        ...

        // send object to endpoint of this service
        allGood = allGood &&
            platformDataUploader.upload(serviceName, platformInstallationData);
    }

    return allGood;
}

Упрощенная версия тестового кода выглядит следующим образом:

@Test
public void whenUploadThenExpectedCallsToUploader(@Mocked final PlatformDataUploader platformDataUploader,
        @Mocked final PlatformInstallationData platformInstallationData)
                throws IOException {

    UploaderApplication target = new UploaderApplication();

    new Expectations() {
        {
            platformDataUploader.upload("AP", platformInstallationData);
            result = true;
            times = 1;

            platformDataUploader.upload("VV", platformInstallationData);
            result = true;
            times = 1;
            ...
            THE REST OF THE EXPECTED CALLS 
            ...


        }
    };

    target.execute(params);
}

Когда я выполняю тест, я получаю: «mockit.internal.MissingInvocation: Missing 1 invocation». Это относится к первой строке в ожиданиях, которые я определил.

Проблема, похоже, в том, что второй аргумент в методе загрузки, который является имитацией PlatformInstallationData, не соответствует экземпляру, созданному в коде приложения (хотя этот экземпляр также должен быть имитируемым).

Чтобы попытаться понять, что происходит, я провел тест, в котором я удалил второй аргумент из метода загрузки (из кода приложения и из тестового кода), поэтому ему нужно было только сопоставить строку, например «AP», с строка, которая существует в приложении в этот момент, и в этом случае она совпала правильно. Итак, я знаю, что при таком подходе он может правильно сопоставить строку, но не может сопоставить имитируемый объект PlatformInstallationData.

Меня удивляет такое поведение, так как я был уверен, что раньше мне удавалось создавать ожидания, включающие в себя имитируемые объекты в качестве аргументов метода, и я думал, что это соответствует им правильно.

Может ли кто-нибудь объяснить это поведение и, возможно, предложить, как это следует проверить. Большое спасибо!


person user3441604    schedule 09.12.2015    source источник


Ответы (1)


Я нашел способ написать тест так, чтобы он соответствовал вызовам, и он подтверждает, что ожидаемое количество вызовов выполнено для метода загрузки и что ожидаемые строки передаются в качестве первого аргумента. Я использовал заполнитель «любой» для второго аргумента. Это немного некрасиво, потому что мне нужно делать гипс. Как показано ниже:

@Test
public void whenUploadThenExpectedCallsToUploader(@Mocked final PlatformDataUploader platformDataUploader,
        @Mocked final PlatformInstallationData platformInstallationData)
                throws IOException {

    InstallPlatformCommand target = new InstallPlatformCommand(Action.INSTALL_PLATFORM);

    new Expectations() {
        {
            platformDataUploader.upload("AP", (PlatformInstallationData) any);
            result = true;
            times = 1;

            platformDataUploader.upload("VV", (PlatformInstallationData) any);
            result = true;
            times = 1;

            ...
            The rest of the expected calls
            ...
        }
    };

    target.execute(params);
}

Я уверен, что есть другие способы сделать это. Если у вас есть более чистый способ, дайте мне знать.

person user3441604    schedule 10.12.2015
comment
Вероятно, вам не нужно издеваться над PlatformInstallationData, поэтому я бы удалил этот фиктивный параметр. Альтернативой (X) any является использование withInstanceOf(PlatformInstallationData.class). Наконец, вы можете записать последовательность значений, переданных параметру serviceName, в локальный список с помощью withCapture(List<String>), а затем сравнить ее с входным списком с помощью assertEquals; это позволило бы тесту записать единственное ожидание для метода upload. - person Rogério; 10.12.2015