denomongo-unittest-utils

Contributions welcome tag CI GitHub Issues
Simple Deno Module to provide Spy Mocks for creating Unittests with mongo published here

Purpose

The purpose of this module is to help with creating Unit-Tests for applications that use the mongo driver for deno.
The module provides Test Doubles for Mongo Collections. More specifically the Test Doubles can be configured as Mocks or Spies according to Martin Fowler's definition. The functionality of a spy object is provided out-of-the-box, the functionality of a mock object can be achieved by passing arguments to the initMock() function as shown below.

meaning that their behaviour can be adjusted and function calls can be asserted with the mock package.

Prerequisites

To use this module efficiently, you should outsource each mongo collection into a seperate file and export the collection as default. By doing this, you can easily redirect the imports of this collection easily via an import map as shown in the usage example below.

Installation

This is a Deno Module available at the deno registry. Before looking at the usage example it, download and install Deno.
Run the unittests with deno test.
Analyze the code coverage with deno test --coverage=./cov and deno coverage ./cov

Usage Example

The following usage example can be viewed in /examples/simple_example and refer to the README for instructions to run the code yourself. Please note that you have to call mockCollection.initMock() also if you don't want to specify special behaviours. To reset the mockCollection / change the behaviour, e.g. for a different test case, simply call mockCollection.initMock() again.

exampletest.ts

//prodCollection will be replaced by the mockCollection via import map
import prodCollection from "./prodCollection.ts";
import { MockCollection } from "https://deno.land/x/denomongo_unittest_utils@VERSION/mod.ts"
import { Filter, FindOptions } from "https://deno.land/x/mongo@v0.29.2/mod.ts"
import {assertSpyCallAsync, Spy} from "https://deno.land/x/mock@0.13.0/mod.ts"

//example function to be tested
function exampleDatabaseCall() {
    prodCollection.findOne({ id: "example" }, {limit: 1})
}


Deno.test("simple example", () => {
    //define the MockCollections behaviour when calling the findOne function
    MockCollection.initMock({
        findOne: (_filter?: Filter<unknown> | undefined, _options?: FindOptions | undefined): Promise<unknown> => {
            return new Promise((resolve, _reject) => {
                resolve({ id:"example"})
            })
        }
    })

    //execute the function
    exampleDatabaseCall()

    //check whether the findOne Method was called correctly and returned the correct values
    assertSpyCallAsync(MockCollection.getInstance().findOne as Spy<any>, 0, {args: [{id: "example"}, {limit: 1}], returned: {id: "example"}})

})

import_map.json

{
    "imports":{
        "./prodCollection.ts" : "https://deno.land/x/denomongo_unittest_utils@VERSION/mod.ts"
    }
}

prodCollection.ts

import { MongoClient} from "https://deno.land/x/mongo@v0.29.2/mod.ts"

interface IExample {
    id: string
}
//MongoClient is not connected in this case, because it is not the focus of this example
export default new MongoClient().database().collection("ExampleCollection")

Further explanations

The module exports a class that has a static attribute instance. Upon initializing the mockCollection by calling ìnitMock(), the instance attribute will be filled. The module exports an instance of this class as default, which proxies every call to the according function on the mock. This allows the prodCollection to be replaced by the mock via the import map at startup while being able to set the mocks behaviour at runtime.