{"id":13807879,"url":"https://github.com/noenv/vertx-wiremongo","last_synced_at":"2025-07-12T05:31:52.295Z","repository":{"id":40994595,"uuid":"243788128","full_name":"NoEnv/vertx-wiremongo","owner":"NoEnv","description":"Lightweight mongo mocking for Vert.x","archived":false,"fork":false,"pushed_at":"2024-11-13T16:30:41.000Z","size":479,"stargazers_count":10,"open_issues_count":0,"forks_count":5,"subscribers_count":8,"default_branch":"main","last_synced_at":"2024-11-13T17:25:09.742Z","etag":null,"topics":["integration-testing","mock","mongodb","mongomock","test","vertx","vertx-mongo-client"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/NoEnv.png","metadata":{"files":{"readme":"README.adoc","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-02-28T15:02:08.000Z","updated_at":"2024-11-13T16:30:47.000Z","dependencies_parsed_at":"2024-02-07T14:27:48.701Z","dependency_job_id":"8dffe295-7e49-4516-a362-d2aa0e6d0a89","html_url":"https://github.com/NoEnv/vertx-wiremongo","commit_stats":null,"previous_names":[],"tags_count":63,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NoEnv%2Fvertx-wiremongo","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NoEnv%2Fvertx-wiremongo/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NoEnv%2Fvertx-wiremongo/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NoEnv%2Fvertx-wiremongo/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/NoEnv","download_url":"https://codeload.github.com/NoEnv/vertx-wiremongo/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":225267500,"owners_count":17447167,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["integration-testing","mock","mongodb","mongomock","test","vertx","vertx-mongo-client"],"created_at":"2024-08-04T01:01:31.586Z","updated_at":"2025-07-12T05:31:52.285Z","avatar_url":"https://github.com/NoEnv.png","language":"Java","readme":"image:https://github.com/NoEnv/vertx-wiremongo/actions/workflows/ci.yml/badge.svg[\"Build Status\",link=\"https://github.com/NoEnv/vertx-wiremongo/actions/workflows/ci.yml\"]\nimage:https://codecov.io/gh/NoEnv/vertx-wiremongo/branch/main/graph/badge.svg[\"Code Coverage\",link=\"https://codecov.io/gh/NoEnv/vertx-wiremongo\"]\nimage:https://badgen.net/maven/v/maven-central/com.noenv/vertx-wiremongo[\"Maven Central\",link=\"https://search.maven.org/artifact/com.noenv/vertx-wiremongo\"]\n\n= Vert.x-Wiremongo\n:toc: left\n\nWiremongo is an alternative implementation of the Vert.x `MongoClient` interface that can be used to mock mongo calls. It is most useful for unit testing mongo database code and is more lightweight than running a mongodb instance.\n\n== Quickstart\n\nTo use Vert.x Wiremongo, add the following dependency:\n\n* Maven (in your `pom.xml`):\n\n[source,xml,subs=\"+attributes\"]\n----\n\u003cdependency\u003e\n  \u003cgroupId\u003ecom.noenv\u003c/groupId\u003e\n  \u003cartifactId\u003evertx-wiremongo\u003c/artifactId\u003e\n  \u003cversion\u003e5.0.1\u003c/version\u003e\n\u003c/dependency\u003e\n----\n\n* Gradle (in your `build.gradle` file):\n\n[source,groovy,subs=\"+attributes\"]\n----\ncompile 'com.noenv:vertx-wiremongo:5.0.1'\n----\n\nImagine you have a mongodb to keep track of your fruit. In your application you have a class that uses `io.vertx.ext.mongo.MongoClient` for the database operations:\n\n[source,java]\n----\npublic class FruitDatabase {\n\n  private final MongoClient mongo;\n\n  public FruitDatabase(MongoClient mongo) {\n    this.mongo = mongo;\n  }\n\n  public Future\u003cVoid\u003e addApple(int mass, Instant expiration) {\n    return insertFruit(\"apple\", mass, expiration).mapEmpty();\n  }\n\n  public Future\u003cVoid\u003e addBanana(int mass, Instant expiration) {\n    return insertFruit(\"banana\", mass, expiration).mapEmpty();\n  }\n\n  private Future\u003cString\u003e insertFruit(String type, int mass, Instant expiration) {\n    var p = Promise.\u003cString\u003epromise();\n    mongo.insert(\"fruits\", new JsonObject()\n      .put(\"type\", type)\n      .put(\"mass\", mass)\n      .put(\"expiration\", new JsonObject().put(\"$date\", expiration)), p);\n    return p.future();\n  }\n\n  public Future\u003cLong\u003e countFruitByType(String type) { }\n  public Future\u003cLong\u003e removeExpiredFruit() { }\n  // etc.\n}\n----\n\nTo test this class, simply create an instance of `WireMongo`, set up some mocking using its fluent methods, and use it as the `MongoClient` implementation in your tests:\n\n[source,java]\n----\n@RunWith(VertxUnitRunner.class)\npublic class FruitDatabaseTest {\n\n  private WireMongo wiremongo;\n  private FruitDatabase db;\n\n  @Before\n  public void setUp() {\n    wiremongo = new WireMongo();\n    db = new FruitDatabase(wiremongo.getClient());\n  }\n\n  @Test\n  public void testAddApple(TestContext ctx) {\n    var expiration = Instant.now().plus(5, ChronoUnit.DAYS);\n\n    wiremongo.insert()\n      .inCollection(\"fruits\")\n      .withDocument(new JsonObject()\n        .put(\"type\", \"apple\")\n        .put(\"mass\", 161)\n        .put(\"expiration\", new JsonObject().put(\"$date\", expiration)))\n      .returnsObjectId();\n\n    db.addApple(161, expiration)\n      .onComplete(ctx.asyncAssertSuccess());\n  }\n}\n----\n\nYou can also test error cases:\n\n[source,java]\n----\n@Test\npublic void testInsertError(TestContext ctx) {\n  wiremongo.insert()\n    .returnsDuplicateKeyError();\n\n  db.addApple(123, Instant.now().plus(3, ChronoUnit.DAYS))\n    .onComplete(ctx.asyncAssertFailure());\n}\n----\n\n_You can find the complete source code of these examples in `src/test/java/com/noenv/wiremongo/examples`._\n\n== Matching\n\nWhen setting up a mock, all the matching criteria can also be defined by *custom matchers*. The following mock would match all `update` commands that try to update the expiration of bananas:\n\n[source,java]\n----\nwiremongo.updateCollection()\n  .inCollection(\"fruits\")\n  .withQuery(q -\u003e q.getString(\"type\").equals(\"banana\"))\n  .withUpdate(u -\u003e u.getJsonObject(\"$set\").containsKey(\"expiration\"))\n  .returnsTimeoutException();\n----\n\nIf you don't specify a custom matcher, `Objects.equals` is used by default. Since a lot of interaction with mongo happens using `JsonObject` and `JsonArray`, there is also a `JsonMatcher` that can be used like this:\n\n[source,java]\n----\nimport static com.noenv.wiremongo.matching.JsonMatcher.equalToJson;\n\nwiremongo.insert()\n  .inCollection(\"fruits\")\n  .withDocument(equalToJson(new JsonObject().put(\"type\", \"banana\"), /*ignoreExtraElements*/ true))\n  .returns(\"2ad7533f\");\n----\n\nThe above example matches all commands that try to insert *bananas* into *fruits*. Note that the json matcher supports a flag `ignoreExtraElements` that allows these insert documents to be matched even if they contain additional fields (e.g. mass \u0026 expiration).\n\n=== Priority\n\nIf several mocks are set up for the same command and matching criteria, WireMongo will use the mock with the highest priority. The default behaviour is to give mocks an increasing priority as they are added so the most recently added always has the highest priority:\n\n[source,java]\n----\nwiremongo.count().inCollection(\"fruits\").returns(21L);\nwiremongo.count().inCollection(\"fruits\").returns(42L);\n\n// a call to mongo.count(\"fruits\") will return 42\n----\n\nHowever, priorities can be user-defined:\n\n[source,java]\n----\nwiremongo.count().inCollection(\"fruits\").priority(13).returns(21L);\nwiremongo.count().inCollection(\"fruits\").priority(11).returns(42L);\n\n// a call to mongo.count(\"fruits\") will return 21\n----\n\n== Stubs\n\nStubs are the *response* part of the mock, i.e. they define how the mock *responds* to commands that match. The most low-level stubs are *custom stubs*:\n\n[source,java]\n----\nwiremongo.findOne()\n  .inCollection(\"fruits\")\n  .stub(c -\u003e new JsonObject()\n    .put(\"type\", \"apple\")\n    .put(\"mass\", 123)\n    .put(\"expiration\", new JsonObject().put(\"$date\", Instant.now())));\n----\n\nSometimes it may be useful to assert that the application actually invokes the expected mongo command:\n\n[source,java]\n----\n@Test\npublic void testInsert(TestContext ctx) {\n  Async async = ctx.async();\n  wiremongo.insert()\n    .stub(c -\u003e {\n      async.countDown();\n      return \"37bd238fa\";\n    });\n\n  application.addApple(); // adding an apple should trigger an insert command\n}\n----\n\nThe `returns(\"1234\")` method is just a more convenient way for `stub(c -\u003e \"1234\")`.\n\nStubs can also throw exceptions:\n\n[source,java]\n----\nwiremongo.count()\n  .stub(c -\u003e { throw new MongoTimeoutException(\"intentional\"); });\n----\n\nFor the most common errors, wiremongo contains helper methods that match the types and messages of an actual mongo instance (`returnsDuplicateKeyError`, `returnsTimeoutException`, `returnsConnectionException`).\n\nMultiple stubs can be configured for a mock. The stubs are used once each in the order they are added, the last one is used forever. Consider the following mock:\n\n[source,java]\n----\nwiremongo.insert()\n  .returns(\"37bd238fa\")\n  .returns(\"73ab6cf21\")\n  .returnsDuplicateKeyError();\n----\n\nThe above code will return ids for the first two and a duplicate key error for every subsequent insert command.\n\n== Match All\n\nIf you want to add a mapping that matches *all* mongo commands, you can use `matchAll`:\n\n[source,java]\n----\nwiremongo.matchAll()\n  .stub(c -\u003e {\n    ctx.assertTrue(c.method().equals(\"replaceDocuments\") || c.method().equals(\"insert\"));\n    log(\"mongo received command: \" + c);\n    return 42;\n  });\n----\n\nMatch All is not supported for file mappings however.\n\n== Files\n\nMocks can also be defined in json files. You can ask wiremongo to read files from a directory like this:\n\n[source,java]\n----\n@Before\npublic void setUp(TestContext ctx) {\n  wiremongo = new WireMongo(vertx);\n  wiremongo.readFileMappings(\"test/resources/wiremongo-files\")\n    .onComplete(ctx.asyncAssertSuccess());\n}\n----\n\nThe wiremongo json files look like this:\n\n[source,json]\n----\n{\n  \"method\": \"insert\",\n  \"collection\": {\n    \"equalTo\": \"fruits\"\n  },\n  \"document\": {\n    \"equalToJson\": {\n      \"type\": \"banana\",\n      \"mass\": 7533\n    },\n    \"ignoreExtraElements\": true\n  },\n  \"response\": \"388adf7ab\"\n}\n----\n\nThe details depend on the command that is mocked. To get started, it is easiest to just look at the json file for the command you want to mock in the `src/test/resources/wiremongo-mocks` folder of this project.\n\n== Verifications\n\nVery often it is not only important to have mocks for a database ready, but also to make sure those are used or even used properly. Verifications let you check if a call to database is made at all, or made for specific times or even never made.\n\nBasic setup for verification is to have a `Verifier` and make sure it is reset before each test and all its verifications are asserted after each test. For example using JUnit:\n\n[source,java]\n----\npublic class SomeTestClass {\n\n  private Verifier verifier;\n\n  @Before\n  public void setUpTest() {\n    verifier = new Verifier();\n  }\n\n  @After\n  public void tearDownTest() {\n    verifier.assertAllSucceeded();\n  }\n\n  // your tests go here\n}\n----\n\nThen each mock can define a verification when it is set up. For example:\n\n[source,java]\n----\npublic class SomeTestClass {\n    // ...\n    @Test\n    public void verify_RunExactlyOnce_shall_fail_ifRunTwice(TestContext ctx) {\n        // ...\n\n        mock\n          .findOneAndUpdate()\n          .inCollection(\"some-collection\")\n          .verify(\n            verifier\n              .checkIf(\"find one and update in some-collection\")\n              .isRunExactlyOnce()\n          )\n          .returns(null);\n\n        // ...\n    }\n}\n----\n\nThe requirements defined will be checked for in the `@After` annotated method.\n","funding_links":[],"categories":["Testing"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnoenv%2Fvertx-wiremongo","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnoenv%2Fvertx-wiremongo","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnoenv%2Fvertx-wiremongo/lists"}