Comment se moquer de spring rabbitmq/amqp pour ne pas échouer lors d'un test de démarrage de printemps lors de la tentative de création automatique d'échanges/de files d'attente?
Étant donné que j’ai une simple RabbitListener
qui créera automatiquement la file et l’échange de la manière suivante:
@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) {
...
}
}
Pendant un simple test de démarrage du printemps, comme ceci:
@ActiveProfiles("test")
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, classes = { Application.class })
@Autowired
private ApplicationContext applicationContext;
@Test
public void test() {
assertNotNull(applicationContext);
}
}
il échouera avec:
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)
Dans ce test, je me fiche de Lapin/AMQP, alors comment puis-je me moquer de tout le Lapin/AMQP?
Ce n'est pas particulièrement facile, nous utilisons généralement un JUnit @Rule
pour ignorer le test si le courtier n'est pas disponible.
Cependant, nous avons beaucoup de tests qui utilisent des simulacres, mais vous devez vraiment comprendre une bonne partie des internes de Spring AMQP pour pouvoir les utiliser. Vous pouvez explorer les cas de test dans le projet lui-même .
À un moment donné, j’ai tenté d’écrire un faux courtier, mais c’était trop de travail.
Je sais que c'est un vieux sujet, mais j'aimerais vous présenter une bibliothèque moqueuse que je développe: rabbitmq-mock .
Le but de cette simulation est d’imiter le comportement de RabbitMQ sans IO (sans démarrer un serveur, écouter de port, etc.) et avec un temps de démarrage mineur (~ aucun).
Il est disponible dans Maven Central:
<dependency>
<groupId>com.github.fridujo</groupId>
<artifactId>rabbitmq-mock</artifactId>
<version>1.0.9</version>
<scope>test</scope>
</dependency>
L’utilisation de base consistera à remplacer la configuration de Spring par un test:
@Configuration
@Import(AmqpApplication.class)
class AmqpApplicationTestConfiguration {
@Bean
public ConnectionFactory connectionFactory() {
return new CachingConnectionFactory(MockConnectionFactoryFactory.build());
}
}
Pour vous moquer automatiquement des haricots du printemps à des fins de test, jetez un œil à un autre projet sur lequel je travaille: spring-automocker
J'espère que cela peut aider!
Je ne suis pas sûr que cela soit utile, mais j'avais le même problème. Donc, je viens d'utiliser @MockBean
sur RabbitAdmin
avec un profil différent, et je n'ai pas eu les mêmes problèmes de connexion. Tests réussis.
@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
}
Dans notre projet, nous initialisons une instance RabbitMQ
à l'aide d'un conteneur docker
localement. Pour exécuter un test d'intégration, nous activons une instance RabbitMQ
au début du scénario de test et nous la fermons pendant le nettoyage.
Nous utilisons TestContainers pour faire exactement cela. Veuillez consulter https://www.testcontainers.org/usage/dockerfile.html et/ou https://www.testcontainers.org/usage/docker_compose.html .
J'avais une exigence similaire à un moment donné et j'ai examiné QPid, qui fournit un courtier AMQP en mémoire. Cela vous oblige à rester au niveau AMQP et à utiliser le moins possible de code spécifique à RabbitMq.
Mais j’ai en fait trouvé une autre solution: en modifiant les noms des files d’attente et des échanges lors de l’exécution de tests + de la valeur de suppression automatique, le problème ne se pose plus. Tous les noms de file d'attente/d'échange dans les tests sont suffixés du nom d'utilisateur (du compte qui exécute les tests), ce qui signifie que tout le monde peut exécuter les tests sur sa machine sans en affecter les autres.
Même dans notre pipeline CI, plusieurs projets peuvent utiliser les mêmes échanges/files d'attente: nous configurons les valeurs dans les tests de manière à ce qu'ils soient spécifiques au projet. Ainsi, même si 2 projets exécutent leurs tests en même temps sur le même ordinateur avec le même utilisateur, des messages sont envoyés. ne "coulera" pas en dehors du test en cours.
Cela finit par être beaucoup plus simple à gérer que de se moquer ou de générer un courtier en mémoire.