我想确保@Transactional注释工作,所以我写了一篇测试save and Publishing文章--我的kafka publisher是一个模拟,它会在任何调用上抛出异常。我想确保MongoDB回滚持久化的文章。
@Test
void testRollbackOnPublishFail() {
when(producer.publishArticle(any())).thenThrow(IllegalStateException.class);
ArticleDocument articleDocument = ArticleTestDataUtil.createArticleDocument();
try {
ArticleDocument publishedDocument = articleService.saveAndPublish(articleDocument);
} catch (Exception e) {
assertTrue(e instanceof IllegalStateException);
}
assertFalse(articleService.findById(articleDocument.getId()).isPresent());
}
testCompile "de.flapdoodle.embed:de.flapdoodle.embed.mongo:2.2.0"
@Configuration
public class MongoTransactionConfig {
@Bean
public MongoTransactionManager transactionManager(MongoDbFactory dbFactory) {
return new MongoTransactionManager(dbFactory);
}
}
现在我的测试失败了,因为无法在MongoClient中启动会话
com.mongodb.MongoClientException: Sessions are not supported by the MongoDB cluster to which this client is connected
at com.mongodb.MongoClient.startSession(MongoClient.java:560)
我还尝试创建一个自定义的IMongodConfig
@Bean(name = "customReplicaMongodConfig")
public IMongodConfig mongodConfig(EmbeddedMongoProperties embeddedProperties) throws IOException {
Storage storage = new Storage("/tmp", "rs0", 0);
return new MongodConfigBuilder()
.shardServer(true)
.version(Version.V4_0_2)
.net(new Net(27117, Network.localhostIsIPv6()))
.replication(storage)
.cmdOptions(new MongoCmdOptionsBuilder().useNoJournal(false).build()).build();
}
并启动复制:
@ConditionalOnBean(name = "customReplicaMongodConfig")
@Configuration
public class ReplicaConfig {
@Inject
private MongoClient mongoClient;
@PostConstruct
public void initiateReplicationSet() {
mongoClient.getDatabase("admin").runCommand(new Document("replSetInitiate", new Document()));
}
}
因此,我的问题是,是否有可能创建一个运行的复制集与嵌入MongoDB测试事务性。
您可以在这里找到有关创建副本集的信息
我的科特林解决方案:
import com.mongodb.BasicDBList
import com.mongodb.BasicDBObjectBuilder
import com.mongodb.DBObject
import com.mongodb.client.MongoClient
import com.mongodb.client.MongoClients
import com.mongodb.client.MongoCollection
import com.mongodb.client.MongoDatabase
import de.flapdoodle.embed.mongo.MongodExecutable
import de.flapdoodle.embed.mongo.MongodProcess
import de.flapdoodle.embed.mongo.MongodStarter
import de.flapdoodle.embed.mongo.config.MongoCmdOptionsBuilder
import de.flapdoodle.embed.mongo.config.MongodConfigBuilder
import de.flapdoodle.embed.mongo.config.Net
import de.flapdoodle.embed.mongo.distribution.Version
import de.flapdoodle.embed.process.runtime.Network
import org.assertj.core.api.Assertions.assertThat
import org.bson.Document
import org.junit.jupiter.api.Test
import org.springframework.data.mongodb.MongoDatabaseFactory
import org.springframework.data.mongodb.MongoTransactionManager
import org.springframework.data.mongodb.core.MongoTemplate
import org.springframework.data.mongodb.core.SimpleMongoClientDatabaseFactory
import org.springframework.test.context.ActiveProfiles
import org.springframework.transaction.TransactionStatus
import org.springframework.transaction.support.TransactionCallbackWithoutResult
import org.springframework.transaction.support.TransactionTemplate
import java.io.IOException
@ActiveProfiles("test")
class EmbeddedMongoDbTransactionTest {
private val CONNECTION_STRING = "mongodb://%s:%d/"
private var node1MongodExe: MongodExecutable? = null
private var node1Mongod: MongodProcess? = null
private var mongo: MongoClient? = null
private var node2MongodExe: MongodExecutable? = null
private var node2Mongod: MongodProcess? = null
@Test
@Throws(IOException::class)
fun testSmth() {
val runtime = MongodStarter.getDefaultInstance()
val node1Port = 57023
val node2Port = 57024
try {
node1MongodExe = runtime.prepare(
MongodConfigBuilder().version(Version.Main.PRODUCTION)
.withLaunchArgument("--replSet", "rs0")
.cmdOptions(MongoCmdOptionsBuilder().useNoJournal(false).build())
.net(Net(node1Port, Network.localhostIsIPv6())).build()
)
node1Mongod = node1MongodExe?.start()
node2MongodExe = runtime.prepare(
MongodConfigBuilder().version(Version.Main.PRODUCTION)
.withLaunchArgument("--replSet", "rs0")
.cmdOptions(MongoCmdOptionsBuilder().useNoJournal(false).build())
.net(Net(node2Port, Network.localhostIsIPv6())).build()
)
node2Mongod = node2MongodExe?.start()
mongo = MongoClients.create(CONNECTION_STRING.format("localhost", node1Port))
val adminDatabase: MongoDatabase = mongo!!.getDatabase("admin")
val config = Document("_id", "rs0")
val members = BasicDBList()
members.add(Document("_id", 0).append("host", "localhost:$node1Port"))
members.add(Document("_id", 1).append("host", "localhost:$node2Port"))
config.put("members", members)
adminDatabase.runCommand(Document("replSetInitiate", config))
println(">>>>>> wait")
println(">>>>>>>>" + adminDatabase.runCommand(Document("replSetGetStatus", 1)))
Thread.sleep(15_000) // without waiting fails with error : 'not master' on server
val funDb: MongoDatabase = mongo?.getDatabase("fun")!!
// insert test 1
val testCollection: MongoCollection<Document> = funDb.getCollection("test")
println(">>>>>>>> inserting data")
testCollection.insertOne(Document("fancy", "value"))
println(">>>>>>>> finding data")
assertThat(testCollection.find().first()!!.get("fancy")).isEqualTo("value")
// insert test 2 (with transaction)
val mongoTemplate = MongoTemplate(mongo!!, "test")
// Without creating collection in advance fails with error:
// Cannot create namespace in multi-document transaction
// (https://stackoverflow.com/questions/52585715/cannot-create-namespace-in-multi-document-transactionmongodb-4-0-spring-data-2)
mongoTemplate.createCollection("collection")
val mongoDatabaseFactory: MongoDatabaseFactory = SimpleMongoClientDatabaseFactory(mongo!!, "test")
val mongoTransactionManager = MongoTransactionManager(mongoDatabaseFactory)
val transactionTemplate = TransactionTemplate(mongoTransactionManager)
transactionTemplate.execute(object : TransactionCallbackWithoutResult() {
override fun doInTransactionWithoutResult(status: TransactionStatus) {
val objectToSave = BasicDBObjectBuilder.start()
.add("key", "value")
.get()
// when
mongoTemplate.save(objectToSave, "collection")
// then
assertThat(mongoTemplate.findAll(DBObject::class.java, "collection"))
.extracting("key")
.containsOnly("value")
}
})
// after transaction
assertThat(mongoTemplate.findAll(DBObject::class.java, "collection"))
.extracting("key")
.containsOnly("value")
} finally {
println(">>>>>> shutting down")
mongo?.close()
node1MongodExe?.stop()
node1Mongod?.stop()
node2MongodExe?.stop()
node2Mongod?.stop()
}
}
}
我在这里读了很多与这个配置相关的问题,但没有一个与我的问题相关。例如如何使用spring boot和spring data配置两个mongodb实例 flapdoodle配置对此有一个实现,但我不确定如何访问它。 https://github.com/flapdoodle-oss/de.flapdoodle.embedd.mongo/blob/master/src/main/java/de/fla
我有一个推送到GitHub的SpringBoot项目,其中我有一些半集成测试,其中我使用嵌入式mongo作为数据库。我的构建在本地是成功的,测试正在通过,但是在运行“MavenJava”GitHub操作时,它会失败,原因如下:
问题内容: 我想测试嵌入式设备的功能。为简化起见,我可以说这是一个人形机器人,由PC通过C / C ++ API进行远程控制。 我非常有兴趣使用它,因为它没有样板方法。但是,我的情况要复杂一些。实际测试在C#程序上运行,大约需要24小时才能完成。通过切换到Python,我可能会节省大量开发新测试的时间。但是,在这样做之前,我正在寻找一些答案。 古老的测试套件的第一个问题是,所有测试都以预定的顺序执
与@mockbean和@spybean一样,有没有类似于@fakebean/@dummybean的东西? 其思想是,该实例是100%真实的(具有预期的生产内部状态),并且它覆盖(或者添加bean,以防在配置中没有声明)上下文中的bean。理想情况下,您不需要创建TestConfiguration类并将其设置为Primary,因为这样可以在每个测试的基础上控制假冒,只有在需要时才可以。否则它使用主的
我在GET api中有多个查询参数(如姓名、年龄、性别、位置等…n个数字)。现在我需要使用这些查询值来查询我的mongo数据库。现在用户可以发送从0到n的查询参数。 我正在尝试使用类似的东西 或者 但问题是,考虑到用户可以发送的所有排列和组合,我将不得不编写多个查询。有没有更好的方法来做到这一点?
我正在使用以下依赖项: 创建了新的测试类: 我在Spring Boot中创建了测试用例,但是我得到了这个错误: 这是我的应用程序类: 知道我为什么不能在测试类中注入bean吗? 我按照建议删除了@ContextConfiguration,@ComponentScan,@ConnecationTes现在我看到了不同的异常: