如何对使用 AlienFactory 的 afIoc 和 afMorphia 框架的 Fantom DAO class 进行单元测试?
How to unit-test a Fantom DAO class that uses AlienFactory's afIoc and afMorphia frameworks?
假设我有一个简单的 Fantom 应用程序可以从 MongoDB 数据库中检索数据。该应用程序使用 afIoc(AlienFactory 的 IoC 框架)和 afMorphia(AlienFactory 的 MongoDB 框架)。我有一个名为 Foo 的简单实体和一个 DAO class (FooDao) 来从数据库中检索 Foo 实体。我想使用 fant 命令测试 DAO class,但出现以下错误。我做错了什么或者有更好的方法来编写测试?。请注意,此应用不使用 afBedSheet 网络框架。
TEST FAILED
afIoc::IocErr: No dependency matches type sys::Type.
Ioc Operation Trace:
[ 1] Injecting dependencies into fields of testAfIoc::FooDaoTest
[ 2] Injecting dependencies into fields of testAfIoc::FooDaoTest
[ 3] Looking for dependency of type testAfIoc::FooDao?
[ 4] Creating REAL Service 'testAfIoc::FooDao'
[ 5] Creating 'testAfIoc::FooDao' via ctor autobuild
[ 6] Injecting dependencies into fields of testAfIoc::FooDao
[ 7] Looking for dependency of type afMorphia::Datastore?
[ 8] Creating REAL Service 'afMorphia::Datastore'
[ 9] Creating 'afMorphia::Datastore' via ctor autobuild
[10] Determining injection parameters for afMorphia::DatastoreImpl sys::Void make(sys::Type type, afMongo::Database database, |sys::This->sys::Void| in)
Stack Trace:
afIoc::Utils.stackTraceFilter (Utils.fan:50)
afIoc::RegistryImpl.injectIntoFields (RegistryImpl.fan:253)
testAfIoc::FooDaoTest.setup (FooDaoTest.fan:17)
java.lang.reflect.Method.invoke (Method.java:483)
fan.sys.Method.invoke (Method.java:559)
fan.sys.Method$MethodFunc.callList (Method.java:204)
fan.sys.Method.callList (Method.java:138)
fanx.tools.Fant.runTest (Fant.java:190)
fanx.tools.Fant.test (Fant.java:110)
fanx.tools.Fant.test (Fant.java:32)
fanx.tools.Fant.run (Fant.java:284)
fanx.tools.Fant.main (Fant.java:327)
Time: 377ms
Failed:
testAfIoc::FooDaoTest.testFindAll
***
*** 1 FAILURES [1 tests, 0 methods, 0 verifies]
***
这就是我的 classes 的样子(显式 "using" 语句显示 classes 来自 Fantom pods):
fan/AppModule.fan
using afIoc::Configuration
using afIoc::Contribute
using afIoc::ServiceDefinitions
using afIocConfig::ApplicationDefaults
using afMorphia::MorphiaConfigIds
using afMorphia::Datastore
class AppModule {
@Contribute { serviceType=ApplicationDefaults# }
static Void contributeAppDefaults(Configuration config) {
config[MorphiaConfigIds.mongoUrl] = `mongodb://localhost:27017/foo`
}
static Void defineServices(ServiceDefinitions defs) {
defs.add(FooDao#)
defs.add(Datastore#)
}
}
fan/Foo.fan
using afMorphia::Entity
using afMorphia::Property
using afBson::ObjectId
@Serializable
@Entity { name="foo" }
class Foo {
@Property const ObjectId _id
@Property const Str text
new make(|This| f) { f(this) }
}
fan/FooDao.fan
using afIoc::Inject
using afMorphia::Datastore
class FooDao {
@Inject { type=Foo# }
Datastore? datastore
Foo[] all() {
(Foo[]) datastore.findAll
}
}
fan/FooDaoTest.fan
using afIoc::Inject
using afIoc::RegistryBuilder
using afIocConfig::ConfigModule
using afMorphia::Datastore
class FooDaoTest : Test {
@Inject
FooDao? subject
override Void setup() {
registry := RegistryBuilder().addModules([
AppModule#
,ConfigModule#
,Datastore#
]).build.startup
registry.injectIntoFields(this)
}
Void testFindAll() {
verifyEq ( subject.all.size, 2 )
}
}
build.fan
#! /usr/bin/env fan
using build
class Build : BuildPod {
new make() {
podName = "testAfIoc"
summary = "Testing AF IoC"
version = Version("0.0.1")
depends = [
"sys 1.0+",
"afIoc 2.0.2+",
"afIocConfig 1.0.16+",
"util 1.0+",
"afMongo 1.0.0+",
"afBson 1.0.0+",
"concurrent 1.0.8+",
"afMorphia 1.0.2+"
]
srcDirs = [
`fan/`,
]
meta = [
"proj.name" : "Testing Alien Factory IoC framework",
"afIoc.module" : "testAfIoc::AppModule",
"org.name" : "Foo",
"org.uri" : "http://www.example.com/"
]
}
}
一切都设置正确,您测试 DAO 的方式也恰到好处。 (顺便说一句,Morphia 不需要 Foo
成为 @Serializable
...)
问题出在您构建 Registry
的位置。因为Morphia是一个IoC库,所以需要将Morphia的模块添加到注册表中。另请注意,Datastore
不是模块,不应添加:
在fan/FooDaoTest.fan
using afIoc::Inject
using afIoc::RegistryBuilder
using afIocConfig::ConfigModule
using afMorphia::MorphiaModule
class FooDaoTest : Test {
@Inject
FooDao? subject
override Void setup() {
registry := RegistryBuilder()
.addModule(AppModule#)
.addModulesFromPod("afMorphia")
.addModulesFromPod("afIocConfig")
.build.startup
registry.injectIntoFields(this)
}
Void testFindAll() {
verifyEq ( subject.all.size, 2 )
}
}
构建您自己的 Registry
时,确保添加所有相关的 IoC 模块和库。
我很惊讶代码没有抛出 'Datastore' Service Not Found Err
(这更能说明问题)- 我会调查一下...
编辑:
啊,是的。在您的 AppModule
中,无需将 Datastore
添加为服务。所有库都应在其模块中定义自己的服务,因此您需要做的就是添加该模块(并可能配置一些服务)。
(Morphia 有一个特殊的依赖提供程序来构建 Datastore
个实例,这就是为什么当您将它添加为普通服务时它不起作用的原因。)
从 AppModule
中删除 Datastore
定义并重新 运行 broken 测试给出:
TEST FAILED
afIoc::IocErr: No service matches type afMorphia::Datastore?.
这是(有点)更多的信息,也是我所期望的。
假设我有一个简单的 Fantom 应用程序可以从 MongoDB 数据库中检索数据。该应用程序使用 afIoc(AlienFactory 的 IoC 框架)和 afMorphia(AlienFactory 的 MongoDB 框架)。我有一个名为 Foo 的简单实体和一个 DAO class (FooDao) 来从数据库中检索 Foo 实体。我想使用 fant 命令测试 DAO class,但出现以下错误。我做错了什么或者有更好的方法来编写测试?。请注意,此应用不使用 afBedSheet 网络框架。
TEST FAILED
afIoc::IocErr: No dependency matches type sys::Type.
Ioc Operation Trace:
[ 1] Injecting dependencies into fields of testAfIoc::FooDaoTest
[ 2] Injecting dependencies into fields of testAfIoc::FooDaoTest
[ 3] Looking for dependency of type testAfIoc::FooDao?
[ 4] Creating REAL Service 'testAfIoc::FooDao'
[ 5] Creating 'testAfIoc::FooDao' via ctor autobuild
[ 6] Injecting dependencies into fields of testAfIoc::FooDao
[ 7] Looking for dependency of type afMorphia::Datastore?
[ 8] Creating REAL Service 'afMorphia::Datastore'
[ 9] Creating 'afMorphia::Datastore' via ctor autobuild
[10] Determining injection parameters for afMorphia::DatastoreImpl sys::Void make(sys::Type type, afMongo::Database database, |sys::This->sys::Void| in)
Stack Trace:
afIoc::Utils.stackTraceFilter (Utils.fan:50)
afIoc::RegistryImpl.injectIntoFields (RegistryImpl.fan:253)
testAfIoc::FooDaoTest.setup (FooDaoTest.fan:17)
java.lang.reflect.Method.invoke (Method.java:483)
fan.sys.Method.invoke (Method.java:559)
fan.sys.Method$MethodFunc.callList (Method.java:204)
fan.sys.Method.callList (Method.java:138)
fanx.tools.Fant.runTest (Fant.java:190)
fanx.tools.Fant.test (Fant.java:110)
fanx.tools.Fant.test (Fant.java:32)
fanx.tools.Fant.run (Fant.java:284)
fanx.tools.Fant.main (Fant.java:327)
Time: 377ms
Failed:
testAfIoc::FooDaoTest.testFindAll
***
*** 1 FAILURES [1 tests, 0 methods, 0 verifies]
***
这就是我的 classes 的样子(显式 "using" 语句显示 classes 来自 Fantom pods):
fan/AppModule.fan
using afIoc::Configuration
using afIoc::Contribute
using afIoc::ServiceDefinitions
using afIocConfig::ApplicationDefaults
using afMorphia::MorphiaConfigIds
using afMorphia::Datastore
class AppModule {
@Contribute { serviceType=ApplicationDefaults# }
static Void contributeAppDefaults(Configuration config) {
config[MorphiaConfigIds.mongoUrl] = `mongodb://localhost:27017/foo`
}
static Void defineServices(ServiceDefinitions defs) {
defs.add(FooDao#)
defs.add(Datastore#)
}
}
fan/Foo.fan
using afMorphia::Entity
using afMorphia::Property
using afBson::ObjectId
@Serializable
@Entity { name="foo" }
class Foo {
@Property const ObjectId _id
@Property const Str text
new make(|This| f) { f(this) }
}
fan/FooDao.fan
using afIoc::Inject
using afMorphia::Datastore
class FooDao {
@Inject { type=Foo# }
Datastore? datastore
Foo[] all() {
(Foo[]) datastore.findAll
}
}
fan/FooDaoTest.fan
using afIoc::Inject
using afIoc::RegistryBuilder
using afIocConfig::ConfigModule
using afMorphia::Datastore
class FooDaoTest : Test {
@Inject
FooDao? subject
override Void setup() {
registry := RegistryBuilder().addModules([
AppModule#
,ConfigModule#
,Datastore#
]).build.startup
registry.injectIntoFields(this)
}
Void testFindAll() {
verifyEq ( subject.all.size, 2 )
}
}
build.fan
#! /usr/bin/env fan
using build
class Build : BuildPod {
new make() {
podName = "testAfIoc"
summary = "Testing AF IoC"
version = Version("0.0.1")
depends = [
"sys 1.0+",
"afIoc 2.0.2+",
"afIocConfig 1.0.16+",
"util 1.0+",
"afMongo 1.0.0+",
"afBson 1.0.0+",
"concurrent 1.0.8+",
"afMorphia 1.0.2+"
]
srcDirs = [
`fan/`,
]
meta = [
"proj.name" : "Testing Alien Factory IoC framework",
"afIoc.module" : "testAfIoc::AppModule",
"org.name" : "Foo",
"org.uri" : "http://www.example.com/"
]
}
}
一切都设置正确,您测试 DAO 的方式也恰到好处。 (顺便说一句,Morphia 不需要 Foo
成为 @Serializable
...)
问题出在您构建 Registry
的位置。因为Morphia是一个IoC库,所以需要将Morphia的模块添加到注册表中。另请注意,Datastore
不是模块,不应添加:
在fan/FooDaoTest.fan
using afIoc::Inject
using afIoc::RegistryBuilder
using afIocConfig::ConfigModule
using afMorphia::MorphiaModule
class FooDaoTest : Test {
@Inject
FooDao? subject
override Void setup() {
registry := RegistryBuilder()
.addModule(AppModule#)
.addModulesFromPod("afMorphia")
.addModulesFromPod("afIocConfig")
.build.startup
registry.injectIntoFields(this)
}
Void testFindAll() {
verifyEq ( subject.all.size, 2 )
}
}
构建您自己的 Registry
时,确保添加所有相关的 IoC 模块和库。
我很惊讶代码没有抛出 'Datastore' Service Not Found Err
(这更能说明问题)- 我会调查一下...
编辑:
啊,是的。在您的 AppModule
中,无需将 Datastore
添加为服务。所有库都应在其模块中定义自己的服务,因此您需要做的就是添加该模块(并可能配置一些服务)。
(Morphia 有一个特殊的依赖提供程序来构建 Datastore
个实例,这就是为什么当您将它添加为普通服务时它不起作用的原因。)
从 AppModule
中删除 Datastore
定义并重新 运行 broken 测试给出:
TEST FAILED
afIoc::IocErr: No service matches type afMorphia::Datastore?.
这是(有点)更多的信息,也是我所期望的。