当前位置: 首页 > 知识库问答 >
问题:

播放2.4测试出错:CacheManager已关闭。它不能再使用了

郎宏逸
2023-03-14

我们的应用程序基于Play 2.4、Scala 2.11和Akka。使用的数据库是MySQL。

缓存在我们的应用程序中被大量使用。我们使用Play的默认EhCache进行缓存。

我们的示例代码片段:

import play.api.Play.current
import play.api.cache.Cache

case class Sample(var id: Option[String],
                 //.. other fields
)

class SampleTable(tag: Tag)
  extends Table[Sample](tag, "SAMPLE") {
  def id = column[Option[String]]("id", O.PrimaryKey)
  // .. other field defs
}

object SampleDAO extends TableQuery(new SampleTable(_)) with SQLWrapper {
  def get(id: String) : Future[Sample] = {
    val cacheKey = // our code to generate a unique cache key
    Cache.getOrElse[Future[[Sample]](cacheKey) {
      db.run(this.filter(_.id === id).result.headOption)
    }
  }
}

我们使用Play的内置规范2进行测试。

var id = "6879a389-aa3c-4074-9929-cca324c7a01f"

  "Sample Application " should {
    "Get a Sample" in new WithApplication {
      val req = FakeRequest(GET, s"/v1/samples/$id")
      val result = route(req).get
      assertEquals(OK, status(result))
      id = (contentAsJson(result).\("id")).get.toString().replaceAllLiterally("\"", "")
   }

但是在单元测试中,我们经常会遇到以下错误。

[error]    1) Error in custom provider, java.lang.IllegalStateException: The  CacheManager has been shut down. It can no longer b
e used.
[error]      at play.api.cache.EhCacheModule.play$api$cache$EhCacheModule$$bindCache$1(Cache.scala:181):
[error]    Binding(interface net.sf.ehcache.Ehcache qualified with QualifierInstance(@play.cache.NamedCache(value=play)) to Prov
iderTarget(play.api.cache.NamedEhCacheProvider@7c8b0968)) (via modules: com.google.inject.util.Modules$OverrideModule -> play.ap
i.inject.guice.GuiceableModuleConversions$$anon$1)
[error]      while locating net.sf.ehcache.Ehcache annotated with @play.cache.NamedCache(value=play)
[error]      at play.api.cache.EhCacheModule.play$api$cache$EhCacheModule$$bindCache$1(Cache.scala:182):
[error]    Binding(interface play.api.cache.CacheApi qualified with QualifierInstance(@play.cache.NamedCache(value=play)) to Pro
viderTarget(play.api.cache.NamedCacheApiProvider@38514c74)) (via modules: com.google.inject.util.Modules$OverrideModule -> play.
api.inject.guice.GuiceableModuleConversions$$anon$1)
[error]      while locating play.api.cache.CacheApi annotated with @play.cache.NamedCache(value=play)
[error]      while locating play.api.cache.CacheApi
[error]
[error]    1 error (InjectorImpl.java:1025)
[error] com.google.inject.internal.InjectorImpl$2.get(InjectorImpl.java:1025)
[error] com.google.inject.internal.InjectorImpl.getInstance(InjectorImpl.java:1051)
[error] play.api.inject.guice.GuiceInjector.instanceOf(GuiceInjectorBuilder.scala:321)
[error] play.api.inject.guice.GuiceInjector.instanceOf(GuiceInjectorBuilder.scala:316)
[error] play.api.Application$$anonfun$instanceCache$1.apply(Application.scala:234)
[error] play.api.Application$$anonfun$instanceCache$1.apply(Application.scala:234)
[error] play.utils.InlineCache.fresh(InlineCache.scala:69)
[error] play.utils.InlineCache.apply(InlineCache.scala:62)
[error] play.api.cache.Cache$.cacheApi(Cache.scala:63)
[error] play.api.cache.Cache$.getOrElse(Cache.scala:106

我们期待在解决上述问题或实现专门用于测试的模拟缓存方面获得帮助。

提前谢谢。

共有3个答案

张翰音
2023-03-14

我认为通过伪造缓存来绕过缓存测试是一种糟糕的做法。它使您的测试无效,这都是因为您试图不以可扩展和分布式的方式使用EhCache。更好的方法是实现@Singleton接口,如下所述:https://stackoverflow.com/a/31835029/5736587

多亏了https://stackoverflow.com/users/2145368/mon-calamari

叶茂才
2023-03-14

另一种解决方案是在每次测试开始时调用顺序方法。

class MySpec extends Specification {
  sequential

  ...
}

笔记

parallelExecution in Test := false

也应该在build.sbt文件中设置。

花俊雄
2023-03-14

我有一个类似的问题,所以我剔除了一个缓存实现并将其替换为测试。

class FakeCache extends CacheApi {
  override def set(key: String, value: Any, expiration: Duration): Unit = {}

  override def get[T](key: String)(implicit evidence$2: ClassManifest[T]): Option[T] = None

  override def getOrElse[A](key: String, expiration: Duration)(orElse: => A)(implicit evidence$1: ClassManifest[A]): A = orElse

  override def remove(key: String): Unit = {}
}

覆盖喷射:

class AbstractViewTest extends PlaySpecification {

  def testApp(handler: DeadboltHandler): Application = new GuiceApplicationBuilder()
                                                   .overrides(bind[CacheApi].to[FakeCache])
                                                   .in(Mode.Test)
                                                   .build()

}

你可以看到我如何在GitHub上使用它:https://github.com/schaloner/deadbolt-2-scala/blob/master/code/test/be/objectify/deadbolt/scala/views/AbstractViewTest.scala

 类似资料:
  • 看起来sbt找不到子项目,但我不知道我该如何解决这个错误。顺便说一下,应用程序在2.3.10上可以无缝工作。 我希望有人能帮助我!提前道谢。

  • 下面是我编写测试的方法: 具有私有方法和运行所有其他私有方法的单个公共方法的类。 我在其他类中有一些通用方法,其中一个名为navigation.php。在这个类中,我有所有的方法,这些方法使我能够进入应用程序的特定点。 我所要做的就是,根据一个条件,正确地关闭(或退出,或处置,或任何你想要的)我的测试,而不返回一个错误。我尝试了quit()、close()和dispose(),但可能我用错了。

  • 当我尝试将我的Android应用程序包上传到Google Play控制台时,我会收到一条一般性错误消息:“无法上传。请重试。”。 我已经试过了: 确保我的和在所有上传的工件中是唯一的 确保/是用正确的密钥签署的 重新上传file 重新上传文件 检查google服务的状态,以确保没有大规模停机 问我的高级Android开发怎么了 如何解决此错误并上载我的或?

  • 问题内容: 我想创建2个可以启动和停止背景音频的设备。 这是我的代码: 当我单击时,可以正常工作,可以播放音频。 但是,当我单击时,会出现错误,如果再次单击,将不会再有声音。 这是错误: 我的程序有什么错误? 问题答案: 此SSCCE在这里是“无效结果”,因为音频无例外地重新启动(尝试至少3次)。

  • 这是我的配置: 我已经创建了play2test。mwb使用MySql workbench,我尝试了其他方法,如: 但总是会出现此错误:db的类型为STRING而不是OBJECT 在终端中: 我试图在 并添加了sbt依赖项: 但它没有工作:((((所以我怎么能解决它:(。 如果我的英语不好

  • 我正在做一个项目,它的大部分Junit都失败了。我的工作是修复它们并使其运行。我已经修复了约200个Junit类,但仍有约136个Junit类失败,原因不知道,有时会失败,有时还能工作。试着深入研究问题并将其应用到ehCache中。它正在被关闭。