单元测试在测试spring集成TCP组件时创建名为“amqAdmin”的bean时出错

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了单元测试在测试spring集成TCP组件时创建名为“amqAdmin”的bean时出错相关的知识,希望对你有一定的参考价值。

我正在编写一个边线微服务,它将TCP与传统应用程序进行对话,并在另一方面使用rabbitMQ。我刚刚开始编写测试,因为我一直在更好地理解一切是如何工作的,因为我是Spring的新手。我的应用程序构建,部署和运行正常。

但是,编写干净的测试要复杂一些。我一直在使用spring-integration tcp基本示例模拟我的代码。我开始使用模拟TCPServer来测试我在测试类之外定义的代码。但是模拟的TCPServer仍然是为每个测试类而构建的。所以我将它移动到TCPGatewayTest类中,类似于示例I found

这导致了一些缺少bean的问题,这导致我添加了@ContextConfiguration注释,这让我更进一步。但是现在我还有其他缺豆。我确定我正在使用@ContextConfiguration搞乱我的ApplicationContext。是否有更好的方法使用不同的注释或略微不同的方式执行此操作?我不会去xml路线,如果可能的话,我想避开它。

熟悉的没有限定bean错误:

Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.springframework.amqp.rabbit.connection.ConnectionFactory' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}

我的测试类如下

package org.inc.imo;

@ComponentScan("org.inc")
@ContextConfiguration(classes = {TCPGatewayTest.TCPServerMock.class, 
                                 org.inc.imo.Configuration.TCPConfig.class, 
                                 org.inc.imo.Configuration.RabbitConfig.class })
@TestPropertySource(locations= "classpath:test.properties")
@RunWith(SpringRunner.class)
@SpringBootTest
public class TCPGatewayTest {

    @Autowired
    private TCPGateway gateway;

    @Autowired
    AbstractServerConnectionFactory crLfServer;

    @Before
    public void setup() {
        TestingUtilities.waitListening(this.crLfServer, 10000L);
    }

    @Test
    public void testConnectionToMockServer() {
        String result = gateway.send("Hello World");

        assertEquals("HELLO WORLD", result);
    }

    @Configuration
    @MessageEndpoint
    public static class TCPServerMock {

        @Value("${imo.port}")
        private int port;

        @Bean()
        public AbstractServerConnectionFactory serverCF() {
            return new TcpNetServerConnectionFactory(this.port);
        }

        @Transformer(inputChannel="fromTcp", outputChannel="toEcho")
        public String convert(byte[] bytes) {
            return new String(bytes);
        }

        @ServiceActivator(inputChannel="toEcho")
        public String upCase(String in) {
            return in.toUpperCase();
        }

        @Bean
        public TcpInboundGateway tcpInGate(AbstractServerConnectionFactory connectionFactory)  {
            TcpInboundGateway inGate = new TcpInboundGateway();
            inGate.setConnectionFactory(connectionFactory);
            inGate.setRequestChannel(fromTcp());
            return inGate;
        }

        @Bean
        public MessageChannel fromTcp() {
            return new DirectChannel();
        }
    }

}

兔子配置类

package org.inc.imo.configuration;

@EnableIntegration
@IntegrationComponentScan
@ComponentScan
@Configuration
public class RabbitConfig {

    public final static String IMO_REQUEST_JEA = "imo.request.jea";

    public final static String IMO_REQUEST_INFO = "imo.request.info";

    @Bean
    public AmqpAdmin amqpAdmin(final ConnectionFactory connectionFactory) {
        RabbitAdmin admin = new RabbitAdmin(connectionFactory);
        admin.declareQueue(jeaRequestQueue());
        admin.declareQueue(infoRequestQueue());
        return admin;
    }

    @Bean
    public Queue jeaRequestQueue() {
        return new Queue(IMO_REQUEST_JEA);
    }

    @Bean
    public Queue infoRequestQueue() {
        return new Queue(IMO_REQUEST_INFO);
    }

    @Bean
    public RabbitTemplate rabbitTemplate(final ConnectionFactory connectionFactory) {
        RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
        rabbitTemplate.setMessageConverter(new Jackson2JsonMessageConverter());

        return rabbitTemplate;
    }

    @Bean
    public ObjectWriter objectWriter() {
        return new ObjectMapper().writer();
    }

}

TCPConfig类

package org.inc.imo.configuration;

@EnableIntegration
@IntegrationComponentScan
@ComponentScan
@Configuration
public class TCPConfig {
    @Value("${imo.hostname}")
    private String host;

    @Value("${imo.port}")
    private int port;

    private static MessageChannel sendChannel;

    private static MessageChannel replyChannel;


    @Bean
    public MessageChannel replyChannel() {
        replyChannel = new DirectChannel();
        return replyChannel;
    }

    @Bean(name="sendChannel")
    public MessageChannel sendChannel() {
        MessageChannel directChannel = new DirectChannel();
        sendChannel = directChannel;
        return directChannel;
    }

    @Bean
    public TcpNetClientConnectionFactory connectionFactory() {
        TcpNetClientConnectionFactory connectionFactory = new TcpNetClientConnectionFactory(host, port);
        connectionFactory.setSingleUse(false);
        return connectionFactory;
    }

    @Bean
    @ServiceActivator(inputChannel = "sendChannel")
    public TcpOutboundGateway tcpOutboundGateway() {
        TcpOutboundGateway tcpOutboundGateway = new TcpOutboundGateway();
        tcpOutboundGateway.setConnectionFactory(connectionFactory());
        tcpOutboundGateway.setReplyChannel(this.replyChannel());
        tcpOutboundGateway.setRequiresReply(true);

        return tcpOutboundGateway;
    }

}

TCPGateway接口

package org.inc.imo.Domain;

@MessagingGateway(defaultRequestChannel = "sendChannel")
public interface TCPGateway {
    String send(String message);
}
答案

例外情况如下:

Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.springframework.amqp.rabbit.connection.ConnectionFactory' available: expected at least 1 bean which qualifies as autowire candidate.

受苦的豆子就像:

@Bean
public AmqpAdmin amqpAdmin(final ConnectionFactory connectionFactory) {
    RabbitAdmin admin = new RabbitAdmin(connectionFactory);
    admin.declareQueue(jeaRequestQueue());
    admin.declareQueue(infoRequestQueue());
    return admin;
}

所以,你在这里请求org.springframework.amqp.rabbit.connection.ConnectionFactory豆注射,但没有人。

如果您只是针对本地RabbitMQ进行测试,那么只需添加一个bean:

@Bean
ConnectionFactory connectionFactory() {
    return new CachingConnectionFactory();
}

你的AmqpAdmin将能够连接到那里。

以上是关于单元测试在测试spring集成TCP组件时创建名为“amqAdmin”的bean时出错的主要内容,如果未能解决你的问题,请参考以下文章

使用junit进行集成spring项目的单元测试

使用junit进行集成spring项目的单元测试

[翻译]Spring Boot 中的集成测试

集成测试框架

Spring 的 MockMvc 是用于单元测试还是集成测试?

spring test组件进行单元测试