我在spring boot应用程序中实现了firebase消息传递。为此,我创建了一个类似本文所述的bean,以便轻松访问FirebaseMessaging
实例。然后,该bean被注入到服务中。然后,当调用利用FirebaseMessaging
bean的服务方法时,所述服务被注入到我的控制器中。
现在我的问题是该项目的测试套件(使用JUnit5
MyControllerTest > testFunction() FAILED
java.lang.IllegalStateException at DefaultCacheAwareContextLoaderDelegate.java:132
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException at ConstructorResolver.java:800
Caused by: org.springframework.beans.factory.BeanCreationException at ConstructorResolver.java:658
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException at ConstructorResolver.java:800
Caused by: org.springframework.beans.BeanInstantiationException at SimpleInstantiationStrategy.java:185
Caused by: org.springframework.beans.factory.BeanCreationException at ConstructorResolver.java:658
Caused by: org.springframework.beans.BeanInstantiationException at SimpleInstantiationStrategy.java:185
Caused by: java.lang.IllegalStateException at Preconditions.java:513
Caused by: java.lang.IllegalStateException at Preconditions.java:513
根本原因:
Caused by: java.lang.IllegalStateException: FirebaseApp name my-app already exists!
at com.google.common.base.Preconditions.checkState(Preconditions.java:513)
at com.google.firebase.FirebaseApp.initializeApp(FirebaseApp.java:222)
at com.google.firebase.FirebaseApp.initializeApp(FirebaseApp.java:215)
at my.example.app.firebase.FirebaseMessagingBean.firebaseMessaging(FirebaseMessagingBean.kt:25)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:78)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:567)
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:154)
... 125 more
注意:这些错误只有在整体运行testsuite时才会出现。如果我自己运行一个测试类,则不会出现错误。
解决这个问题的一种方法是向每个类添加一个@MockBean
,这样测试上下文就会加载bean。因此,我可以继续并简单地将其添加到每个测试类中,但我更希望使用一种方法,将FirebaseMessaging
@MockBean
自动注入到每个测试类中。每当开发人员忘记将@MockBean
添加到他的测试类中时,测试套件不会失败。
实现这一目标的正确方法是什么?
(这段代码是静态编程语言,但我也很乐意接受解决方案的java代码。)
代码:
@Component
class FirebaseMessagingBean {
@Bean
fun firebaseMessaging(): FirebaseMessaging {
val privateKeyFileURL = ClassLoader.getSystemResource("firebase-cloud-messaging.json")
?: throw IOException("Couldn't read firebase credentials")
val privateKeyStream = File(privateKeyFileURL.file).inputStream()
val googleCredentials = GoogleCredentials.fromStream(privateKeyStream)
val firebaseOptions = FirebaseOptions.builder().setCredentials(googleCredentials)
.build()
val app = FirebaseApp.initializeApp(firebaseOptions, "my-app")
return FirebaseMessaging.getInstance(app)
}
}
@Service
class FirebaseNotificationService(
val firebaseMessaging: FirebaseMessaging
) {
fun sendNotification(msg: String) { /* ... */ }
}
@RestController
@RequestMapping("/api/route")
class MyController(
val firebaseNotificationService: FirebaseNotificationService,
) {
@PostMapping()
fun postRoute(): ResponseEntity<Any> {
firebaseNotificationService.sendNotification("msg")
// ...
}
}
测试类示例
@AutoConfigureMockMvc
@SpringBootTest
class DeviceControllerTest {
// injections
@Test
fun testFunction() { /* ... */ }
}
我只在之前没有实例化的情况下初始化FirebasApp实例,从而修复了这个问题。
更新的bean:
class FirebaseMessagingBean {
@Bean
fun firebaseMessaging(): FirebaseMessaging {
val privateKeyFileURL = ClassLoader.getSystemResource("firebase-cloud-messaging.json")
?: throw IOException("Couldn't read firebase credentials")
val privateKeyStream = File(privateKeyFileURL.file).inputStream()
val googleCredentials = GoogleCredentials.fromStream(privateKeyStream)
val firebaseOptions = FirebaseOptions
.builder()
.setCredentials(googleCredentials)
.build()
val app = try {
FirebaseApp.getInstance()
} catch (iae: IllegalStateException) {
FirebaseApp.initializeApp(firebaseOptions)
}
return FirebaseMessaging.getInstance(app)
}
}
问题内容: 我有一些带有自定义注释的类,不应实例化(抽象类,它只是真实bean的子组件)。但是在此类的顶部,在运行时,在上下文初始化阶段,我想将额外的bean放入应用程序上下文中。 因此,基本上,我需要扫描类路径,处理结果,并将新bean引入当前的应用程序上下文中。 似乎spring-mvc,spring-tasks和spring-integration正在这样做(我试图从源中学习它-没运气) 我
我有一些不应该实例化的带有自定义注释的类(抽象类,它只是实际bean的子组件)。但是在这些类之上,在运行时,在上下文初始化阶段,我想在应用程序上下文中添加额外的bean。 因此,基本上我需要扫描类路径,处理结果,并将新bean引入curent应用程序上下文。 似乎是spring-mvc、spring-tasks和spring-integration在做这件事(我试着从源代码中学习--没有运气) 我
我有需要测试的REST服务。该服务具有Spring Security身份验证,我需要在测试或模拟中关闭它。我决定嘲笑它,因为我不能关掉它。我为此编写了,但现在未加载上下文: 在我的主要源代码中,我有一些config类加载了一些其他bean,而it类在我的测试中没有加载,我有一个例外: 我做错了什么?有人能帮我吗?我使用了,但在该版本中,无法工作,因为属性不再存在。
我对Spring Security有这个问题。 我有一个带有SecurityConfig类的java配置实现,它扩展了WebSecurityConfigureAdapter。 在这个类中,我想重写方法“configure()” 一切正常,一切正常。 问题是Spring Context上没有加载“MyDaoAuthenticationProvider”组件。所以我无法注入或自动安装此类中的任何组件:
我在spring TestContext配置的深潜过程中遇到了spring-boot-test问题。 示例项目:github示例项目 我有三个带有bean的Spring配置(-重量级配置,我需要缓存它) 两次然后 只有一次。在我看来,这是可能的,因为已经缓存为TestContext(发生这种情况是因为和包含在同一个包中) 这意味着spring启动我的spring上下文三次!为什么?在日志中查看三次
问题内容: 当您长按Android中的某个按钮时,将显示一个上下文菜单。我想为该系统中的所有菜单添加一些内容。 例如,系统使用“复制和粘贴”来执行此操作。我想添加自己的文件,并将其显示在每个应用程序中。 问题答案: 当前,Android不支持此功能,如果没有特定活动实现您公开的意图或活动,则无法在系统级别全局覆盖或挂钩功能。即使在发布意图的情况下,除非运行的应用程序是使用者也没关系……所有基本系统