wake-up-neo.com

wie man Spring Amqp/Kaninchen im Frühling Boottest verspottet

Wie spottest du den Frühling rabbitmq/amqp, damit er während eines Spring Boot-Tests nicht versagt, während er versucht, automatisch Austausche/Warteschlangen zu erstellen?

Angenommen, ich habe eine einfache RabbitListener, die bewirkt, dass die Warteschlange und der Austausch wie folgt automatisch erstellt werden:

@Component
@RabbitListener(bindings = {
        @QueueBinding(
                value = @Queue(value = "myqueue", autoDelete = "true"), 
                exchange = @Exchange(value = "myexchange", autoDelete = "true", type = "direct"), 
                key = "mykey")}
)
@RabbitListenerCondition
public class EventHandler {
    @RabbitHandler
    public void onEvent(Event event) {
      ...
    }   
}

Während eines einfachen Spring Boot-Tests wie folgt:

@ActiveProfiles("test")
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, classes = { Application.class })

    @Autowired
    private ApplicationContext applicationContext;

    @Test
    public void test() {
        assertNotNull(applicationContext);
    }

}

es wird fehlschlagen mit:

16:22:16.527 [SimpleAsyncTaskExecutor-1] ERROR o.s.a.r.l.SimpleMessageListenerContainer - Failed to check/redeclare auto-delete queue(s).
org.springframework.amqp.AmqpConnectException: Java.net.ConnectException: Connection refused
    at org.springframework.amqp.rabbit.support.RabbitExceptionTranslator.convertRabbitAccessException(RabbitExceptionTranslator.Java:62)
    at org.springframework.amqp.rabbit.connection.AbstractConnectionFactory.createBareConnection(AbstractConnectionFactory.Java:309)

In diesem Test interessiert mich Rabbit/AMQP nicht, also wie kann ich das ganze Rabbit/AMQP verspotten?

6
domi

Es ist nicht besonders einfach, wir verwenden im Allgemeinen einen JUnit @Rule, um den Test zu überspringen, wenn der Broker nicht verfügbar ist.

Wir haben zwar viele Tests, die Mocks verwenden, aber man muss wirklich viel über die Spring AMQP-Interna verstehen, um sie verwenden zu können. Sie können die Testfälle im Projekt selbst untersuchen.

Irgendwann habe ich versucht, einen Scheinbroker zu schreiben, aber es war zu viel Arbeit.

5
Gary Russell

Ich weiß, das ist ein altes Thema, aber ich möchte eine spöttische Bibliothek vorstellen, die ich entwickle: rabbitmq-mock .

Der Zweck dieses Mock besteht darin, das Verhalten von RabbitMQ ohne IO (ohne Starten eines Servers, Abhören eines Ports usw.) und mit geringer Startzeit (~ none) nachzuahmen.

Es ist in Maven Central verfügbar:

<dependency>
    <groupId>com.github.fridujo</groupId>
    <artifactId>rabbitmq-mock</artifactId>
    <version>1.0.9</version>
    <scope>test</scope>
</dependency>

Die grundlegende Verwendung besteht darin, die Federkonfiguration mit einer Testkonfiguration zu überschreiben:

@Configuration
@Import(AmqpApplication.class)
class AmqpApplicationTestConfiguration {

    @Bean
    public ConnectionFactory connectionFactory() {
        return new CachingConnectionFactory(MockConnectionFactoryFactory.build());
    }
}

Für das automatische Verspotten von Spring-Beans für Tests werfen Sie einen Blick auf ein anderes Projekt, an dem ich gerade arbeite: spring-automocker

Hoffe das kann helfen!

7
Loïc Le Doyen

Nicht sicher, ob dies hilfreich ist, aber ich hatte das gleiche Problem. Also habe ich gerade @MockBean für RabbitAdmin mit einem anderen Profil verwendet und ich habe nicht die gleichen Verbindungsprobleme. Tests bestanden.

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE)
@RunWith(SpringRunner.class)
@ActiveProfiles("my-test")
public class ServiceTests {

@Autowired
private DummyService unitUnderTest;

@MockBean
private RabbitAdmin rabbitAdmin;

// lots of tests which do not need Spring to Create a RabbitAdmin Bean
}
3
Raj

In unserem Projekt initialisieren wir eine RabbitMQ-Instanz lokal mit einem docker-Container. Um einen Integrationstest auszuführen, starten wir eine RabbitMQ-Instanz zu Beginn des Testfalls und fahren sie während der Bereinigung herunter.

Wir verwenden TestContainer, um genau das zu tun. Siehe https://www.testcontainers.org/usage/dockerfile.html und/oder https://www.testcontainers.org/usage/docker_compose.html .

2
joy

Ich hatte irgendwann eine ähnliche Anforderung und schaute in QPid nach, was einen AMQP-Broker im Speicher bietet. Sie zwingen Sie dazu, auf AMQP-Niveau zu bleiben und so wenig rabbitMq-spezifischen Code wie möglich zu verwenden. 

Aber ich habe tatsächlich einen anderen Weg gefunden: Durch das Anpassen der Namen von Warteschlangen und des Austauschs beim Ausführen von Tests + des Auto-Delete-Werts haben wir das Problem nicht mehr. Alle Warteschlangennamen in Tests werden mit dem Benutzernamen (des Kontos, in dem die Tests ausgeführt werden) mit einem Suffix versehen. Dies bedeutet, dass jeder die Tests auf dem Computer ausführen kann, ohne die anderen zu beeinträchtigen. 

Sogar in unserer CI-Pipeline können mehrere Projekte dieselben Austausche/Warteschlangen verwenden: Wir konfigurieren die Werte in Tests projektspezifisch, so dass selbst wenn zwei Projekte ihre Tests gleichzeitig auf demselben Rechner mit demselben Benutzer ausführen, Nachrichten angezeigt werden wird nicht außerhalb des aktuellen Tests "lecken". 

Dies ist am Ende viel einfacher zu handhaben, als einen Speicherbroker zu verspotten oder zu spawnen. 

1
Vincent F

Etwas ähnlich wie Rajkishans Antwort das hat bei mir nicht funktioniert:

Das hat bei mir stattdessen funktioniert:

@SpringBootApplication
public class MyTestsApp {
    @Bean
    @Primary
    public CachingConnectionFactory rabbitAdmin() {
        return Mockito.mock(CachingConnectionFactory.class);
    }
}

@RunWith(SpringRunner.class)
@SpringBootTest(classes = {MyTestsApp.class})
@ActiveProfiles(profiles = "test")
public class MyTests {

}
1