Член @Autowired не создается, когда класс подвергается модульному тестированию с использованием @MockBean и PowerMockito - PullRequest
0 голосов
/ 24 марта 2020

В классе, который я тестирую, есть несколько участников с автоматическим подключением, но один из них вызывает у меня проблему. На элемент с автосвязью ссылается интерфейс, а реализация не имеет конструктора по умолчанию. Единственный конструктор имеет аргумент с именем spring bean. Я деконструировал тестируемые классы ниже вместе с тремя различными попытками тестов, которые все терпят неудачу по разным причинам. Если кто-то знает, что я делаю не так, пожалуйста, выделите.

Это свойства и зависимости из файла pom. xml. Обратите внимание, что я использую PowerMockito с EasyMock.

<properties>
    <java.version>1.8</java.version>
    <powermock.version>2.0.2</powermock.version>
</properties>

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.powermock</groupId>
        <artifactId>powermock-module-junit4</artifactId>
        <version>${powermock.version}</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.powermock</groupId>
        <artifactId>powermock-api-easymock</artifactId>
        <version>${powermock.version}</version>
        <scope>test</scope>
    </dependency>
</dependencies>

BaseClass. java с автоматическим элементом

package demo;

import org.springframework.beans.factory.annotation.Autowired;

public class BaseClass {

    @Autowired
    Sample sampleJob; 

    protected void runJob() {
        sampleJob.execute();
    }
}

Пример интерфейса. java

package demo;

public interface Sample {
    public void execute();
}

Класс реализации SampleImpl. java со ссылкой на пружинный компонент

package demo;

import org.springframework.beans.factory.annotation.Qualifier;

public class SampleImpl implements Sample {

    Runnable runnable = null;


    public SampleImpl(@Qualifier("myJob") Runnable job) {
        runnable = job;
    }

    @Override
    public void execute() {

        runnable.run();
    }
}

Наконец контрольный пример джунты. Примечание. PowerMock Runner передает делегирование Spring Runner для создания MockBean. Комментарии в каждом тесте указывают на режим и линию сбоя.

package demo;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import org.powermock.modules.junit4.PowerMockRunnerDelegate;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import static org.powermock.api.easymock.PowerMock.createMock;
import static org.powermock.api.easymock.PowerMock.expectNew;


@RunWith(PowerMockRunner.class)
@PowerMockRunnerDelegate(SpringJUnit4ClassRunner.class)
class BaseClassTests1 {

    @MockBean
    @Qualifier("myJob")
    Runnable mockJob;

    public BaseClassTests1() {}

    @Test
    @PrepareForTest(BaseClass.class)
    public void testSample1() throws Exception {

        Sample mockSample = createMock(Sample.class);
        /* 
         * Try no arg constructor signature fails with:
         * org.powermock.reflect.exceptions.ConstructorNotFoundException: 
         * No constructor found in class 'demo.Sample' with parameter types: [ <none> ].
         */
        expectNew(Sample.class).andReturn(mockSample);

        mockSample.execute();

        BaseClass bc = new BaseClass();
        bc.runJob();

    }

    @Test
    @PrepareForTest(BaseClass.class)
    public void testSample2() throws Exception {

        Sample mockSample = createMock(Sample.class);
        /* 
         * Try including mock job as part of constructor signature fails with:
         * org.powermock.reflect.exceptions.ConstructorNotFoundException: 
         * No constructor found in class 'demo.Sample' with parameter types: 
         * [ org.mockito.codegen.Runnable$MockitoMock$1280448795 ].
         * 
         */
         expectNew(Sample.class, mockJob).andReturn(mockSample);

        mockSample.execute();

        BaseClass bc = new BaseClass();
        bc.runJob();

    }

    @Test
    @PrepareForTest(BaseClass.class)
    public void testSample3() throws Exception {

        SampleImpl mockSample = createMock(SampleImpl.class);
        expectNew(SampleImpl.class, mockJob).andReturn(mockSample);

        mockSample.execute();

        BaseClass bc = new BaseClass();
        /* 
         * Try mock of impl class but fails with :
         * java.lang.NullPointerException 
         *     at demo.BaseClass.runJob(BaseClass.java:11)
         *  because the mock bean mockJob did not get autowired in the BaseClass object
         */
        bc.runJob();

    }
}

Примечание: установка точки останова на b c .runJob () в методе testSample3 и проверка mockSample показывает исполняемый элемент как ноль. Это не то, чего я ожидал, так как в этом тесте не произошел сбой при вызове метода allowNew ().

...