mockito 如何在spring Boot 中为GCP PUB/SUB编写Junit测试用例

roejwanj  于 2023-08-05  发布在  Spring
关注(0)|答案(1)|浏览(131)

我想为GCP pub/sub编写Junit测试用例,但我不知道从哪里开始。我什么都找不到。如果有人能帮助我,这将是很大的帮助。我在下面提供了一些我的代码。

订阅者

@Slf4j
@Component
public class Subscriber{
     @ServiceActivator(inputChannel = "inputMessageChannel")
        public void messageReceiver(
                String payload,
                @Header(GcpPubSubHeaders.ORIGINAL_MESSAGE) BasicAcknowledgeablePubsubMessage message) {
            log.info("Message arrived via an inbound channel adapter from sub-one! Payload: " + payload);
    
            Map<String, String> attributes = message.getPubsubMessage().getAttributesMap();
            log.info(attributes.toString());
            message.ack();
        }
}

字符串

发布者

@Slf4j
@Component
public class Publisher {

    @Autowired
    private PubSubTemplate pubSubTemplate;

    public void publish(String topicName, String message, Map<String, String> attributes) {
        log.info("published to topic " + topicName + " message = " + message);
        pubSubTemplate.publish(topicName, message, attributes);
    }
}

xoshrz7s

xoshrz7s1#

基本上你可以使用Google提供的官方Pub/Sub emulator
Emulator可以从CLI手动运行,如doc中所述,或者您可以使用TestContainers GCloud模块,还有Sping Boot repo的示例使用
如果你选择手动运行它,你可以跳过设置环境变量,因为对于Java来说,还有另一种方法(在文档中有更详细的描述)。也许你已经通过gcloud pubsub ...命令创建了你的主题和订阅,不幸的是模拟器不支持这些命令,所以据我所知,你必须通过SDK在你的应用程序中创建它们。你可以这样做(Kotlin代码)来创建使用模拟器的订阅、主题和发布者。那么你的消息渠道应该选择它。

PubsubConfigLocalAndTest

@Configuration
@Profile("default || test")
class PubsubConfigLocalAndTest {
    private val logger = LoggerFactory.getLogger(this::class.java)

    @Value("\${spring.cloud.gcp.project-id:}")
    lateinit var projectId: String

    @Value("\${spring.cloud.gcp.pubsub.emulator-host:}")
    lateinit var hostport: String

    private val credentialsProvider: CredentialsProvider = NoCredentialsProvider.create()

    @Bean
    fun testTransportChannelProvider(): TransportChannelProvider {
        val channel = ManagedChannelBuilder.forTarget(hostport).usePlaintext().build()
        return FixedTransportChannelProvider.create(GrpcTransportChannel.create(channel))
    }

    @Bean
    fun topics(testTransportChannelProvider: TransportChannelProvider): Array<EventTopics> {
        val topicAdminSettings = TopicAdminSettings.newBuilder()
            .setTransportChannelProvider(testTransportChannelProvider)
            .setCredentialsProvider(credentialsProvider)
            .build()

        TopicAdminClient.create(topicAdminSettings).use { topicAdminClient ->
            EventTopics.values().forEach { topic ->
                try {
                    topicAdminClient.createTopic(projectId, topic.name)
                } catch (e: Exception) {
                    logger.info("Topic not created: ${topic.name}")
                    e.printStackTrace()
                }
            }
        }
        return EventTopics.values()
    }

    @Bean
    fun subscriptions(testTransportChannelProvider: TransportChannelProvider): Array<EventSubscriptions> {
        val subscriptionAdminSettings = SubscriptionAdminSettings.newBuilder()
            .setTransportChannelProvider(testTransportChannelProvider)
            .setCredentialsProvider(credentialsProvider)
            .build()

        SubscriptionAdminClient.create(subscriptionAdminSettings).use { subscriptionAdminClient ->
            EventSubscriptions.values().forEach { subscription ->
                try {
                    subscriptionAdminClient.createSubscription(projectId, subscription.name)
                } catch (e: Exception) {
                    logger.info("Subscription not created: ${subscription.name}")
                    e.printStackTrace()
                }
            }
        }
        return EventSubscriptions.values()
    }

    @Throws(IOException::class)
    private fun SubscriptionAdminClient.createSubscription(projectId: String?, subscriptionId: String?): Subscription? {
        val subscriptionName = SubscriptionName.of(projectId, subscriptionId)
        val topicName =
            TopicName.of(projectId, EventSubscriptions.valueOf(subscriptionId!!).getTopic().name)
        val pushConfig = PushConfig.newBuilder().build()
        val response = this.createSubscription(subscriptionName, topicName, pushConfig, 600)
        logger.info("Created subscription: " + response.name)
        return response
    }

    @Throws(IOException::class)
    private fun TopicAdminClient.createTopic(projectId: String?, topicId: String?): Topic? {
        val topicName = TopicName.of(projectId, topicId)
        val topic = this.createTopic(topicName)
        logger.info("Created topic: " + topic.name)
        return topic
    }
}

字符串

测试的发布服务器还应使用模拟器

fun getPublisher(
        topicName: TopicName,
        channelProvider: TransportChannelProvider? = null,
        env: Environment? = null
    ): Publisher {
        return if (channelProvider != null && (env?.isLocal() == true || env?.isTest() == true)) {
            Publisher.newBuilder(topicName)
                .setChannelProvider(channelProvider)
                .setCredentialsProvider(NoCredentialsProvider.create())
                .setEnableMessageOrdering(true)
                .build()
        } else {
            Publisher.newBuilder(topicName).setEnableMessageOrdering(true).build()
        }
    }

application.yml

cloud:
    gcp:
      project-id: xxx
      pubsub:
        emulator-host: "localhost:8085"


我想你可以在测试用例中构建Topic,并像在3链接中那样使用SubscriberStub,而不是在配置中创建订阅和主题。我发现的另一个资源是medium post,但它是spring-cloud-stream绑定而不是消息通道。
这是一个棘手的主题,我找不到更复杂的设置,所以如果你会发现一些东西,请评论:)

相关问题