Замена bean-компонента Spring с зависимостью Autowired во время тестирования - PullRequest
0 голосов
/ 30 января 2019

Я пытаюсь заставить Spring заменить класс, который имеет автосвязанные зависимости, на другой (тестовый класс), который не имеет этих автопроводных зависимостей, но я всегда получаю исключение NoSuchBeanDefinitionException, например:

Вызывается: org.springframework.beans.factory.NoSuchBeanDefinitionException: нет доступного квалифицирующего компонента типа com.experiment.beanreplacement.client.Connection: ожидается как минимум 1 компонент, который считается кандидатом на автоматическое подключение.Аннотации зависимостей: {@ org.springframework.beans.factory.annotation.Autowired (обязательно = true)}

Я создал упрощенный пример, чтобы показать мою проблему.

У меня есть два класса вмой клиентский пакет (Connection.java и TcpClient.java) и два в моем прикладном пакете (MessageSender.java и Scheduler.java)

package com.experiments.beanreplacement.client;
@Component
public class Connection {
    public void send(String msg) { System.out.println("Connection send: " + msg); }
...

TcpClient.java автоматически связывает класс Connection:

@Component
public class TcpClient {

    @Autowired
    Connection connection;

    public void send(String msg) {
        System.out.println("TcpClient send");
        connection.send(START_OF_MESSAGE + msg + END_OF_MESSAGE);
   }
}

Класс MessageSender использует TcpClient для отправки сообщений:

package com.experiments.beanreplacement.application;    
@Component
public class MessageSender {
    @Autowired
    TcpClient client;

    public void sendAMessage() {
        client.send("Hello world!");
        client.send("Bye bye...");
    }
}

Я настроил тест для запуска этого с использованием JUnit:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"/applicationContext.xml"})
public class MessageSenderTest {

    @Autowired
    MessageSender messageSender;

    @Test
    public void testMessageSender() {
        messageSender.sendAMessage();
    }
}

Класс TcpClientMock:

package client;
@Primary
public class TcpClientMock extends com.experiments.beanreplacement.client.TcpClient{
    @Override
    public void send(String msg) {
        System.out.println("Mock client send: " + msg);
    }
    ...

applicationContext.xml

    <bean class="client.TcpClientMock" name="client" >
    </bean>

    <context:component-scan base-package="com.experiments.beanreplacement.application">
    </context:component-scan>
    ...

В файле applicationContext.xml я заменяю TcpClient, который автоматически подключается в классе MessageSender, на другой (TcpClientMock).

Я настроил компонентное сканирование таким образом, чтобы он смотрел только на пути MessageSender и TcpClientMock, надеясь избежать необходимости иметь дело с зависимостями autowire исходного TcpClient и базового Connection.

Тем не менее, я все еще получаю «Нет подходящего бина типа com.experiment.beanreplacement.client.Connection»: ожидается как минимум 1 бин, который квалифицируется как кандидат для автопроводки ».ошибка, даже если класс, использующий зависимость autowire, не является частью компонентаного сканирования.

Есть ли способ избежать этого?

1 Ответ

0 голосов
/ 30 января 2019

Вы должны быть в состоянии смоделировать ваш TcpClient бин с @MockBean.В тесте добавьте:

@MockBean
TcpClient client;

. В своем методе тестирования вы можете указать поведение метода send() следующим образом:

String msg = "anything";
doAnswer(i -> {
                System.out.println("Mock client send: " + msg);
                return null;
            }
    ).when(client).send(msg);
...