diff --git a/README.md b/README.md
index 767006ed..006483fa 100644
--- a/README.md
+++ b/README.md
@@ -96,7 +96,7 @@ export class DatabaseModule {}
 
 ## Configuration
 
-| Name     | Type     | Required | Default             |
-| -------- | -------- | -------- | ------------------- |
-| `Model`  | `Object` | `false`  | `objection.Model`   |
-| `config` | `Object` | `false`  | Knex default config |
+| Name     | Type     | Required | Default           |
+| -------- | -------- | -------- | ----------------- |
+| `Model`  | `Object` | `false`  | `objection.Model` |
+| `config` | `Object` | `true`   |                   |
diff --git a/jest.config.js b/jest.config.js
index 7324049a..4f9f7ba0 100644
--- a/jest.config.js
+++ b/jest.config.js
@@ -1,6 +1,7 @@
 module.exports = {
   clearMocks: true,
   collectCoverage: true,
+  collectCoverageFrom: ["<rootDir>/lib/**/*.ts", "!**/node_modules/**"],
   coverageDirectory: "coverage",
   coverageReporters: ["json", "text", "lcov"],
   testEnvironment: "node",
diff --git a/lib/core.ts b/lib/core.ts
index 2ca1a21b..83ef0a2d 100644
--- a/lib/core.ts
+++ b/lib/core.ts
@@ -14,10 +14,9 @@ import {
 } from "./interfaces";
 
 export class ObjectionCoreModule {
-  public static forRoot(options: ObjectionModuleOptions = {}): DynamicModule {
-    const knexConfig = options.config || {};
+  public static forRoot(options: ObjectionModuleOptions): DynamicModule {
     const Base = options.Model || Model;
-    const connection = knex(knexConfig);
+    const connection = knex(options.config);
 
     Base.knex(connection);
 
@@ -54,9 +53,7 @@ export class ObjectionCoreModule {
       provide: KNEX_CONNECTION,
       inject: [OBJECTION_MODULE_OPTIONS],
       useFactory(objectionModuleOptions: ObjectionModuleOptions) {
-        const config = objectionModuleOptions.config || {};
-
-        return knex(config);
+        return knex(objectionModuleOptions.config);
       }
     };
 
@@ -93,9 +90,7 @@ export class ObjectionCoreModule {
   ): Provider[] {
     if (options.useExisting || options.useFactory) {
       return [this.createAsyncOptionsProvider(options)];
-    }
-
-    if (!options.useClass) {
+    } else if (!options.useClass) {
       throw new Error("Invalid configuration");
     }
 
diff --git a/lib/interfaces.ts b/lib/interfaces.ts
index 74230ff7..d4f9c38f 100644
--- a/lib/interfaces.ts
+++ b/lib/interfaces.ts
@@ -5,7 +5,7 @@ import { Model } from "objection";
 
 export interface ObjectionModuleOptions {
   Model?: typeof Model;
-  config?: Knex.Config;
+  config: Knex.Config;
 }
 
 export interface ObjectionModuleOptionsFactory {
diff --git a/lib/module.ts b/lib/module.ts
index 4a5ff694..3b27650c 100644
--- a/lib/module.ts
+++ b/lib/module.ts
@@ -8,7 +8,7 @@ import {
 // eslint-disable-next-line new-cap
 @Module({})
 export class ObjectionModule {
-  public static forRoot(options?: ObjectionModuleOptions): DynamicModule {
+  public static forRoot(options: ObjectionModuleOptions): DynamicModule {
     return {
       module: ObjectionModule,
       imports: [ObjectionCoreModule.forRoot(options)]
diff --git a/tests/core.spec.ts b/tests/core.spec.ts
new file mode 100644
index 00000000..49d9e61d
--- /dev/null
+++ b/tests/core.spec.ts
@@ -0,0 +1,198 @@
+import {
+  KNEX_CONNECTION,
+  OBJECTION_BASE_MODEL,
+  OBJECTION_MODULE_OPTIONS
+} from "@/constants";
+import { ObjectionCoreModule } from "@/core";
+import {
+  ObjectionModuleOptions,
+  ObjectionModuleOptionsFactory
+} from "@/interfaces";
+import { Injectable } from "@nestjs/common";
+import { Test, TestingModule } from "@nestjs/testing";
+import knex from "knex";
+import { Model } from "objection";
+
+describe("ObjectionCoreModule", () => {
+  let testingModule: TestingModule;
+  const config: knex.Config = {
+    client: "sqlite3",
+    useNullAsDefault: true,
+    connection: {
+      filename: "./testing.sqlite"
+    }
+  };
+
+  describe("#forRoot", () => {
+    beforeEach(async () => {
+      testingModule = await Test.createTestingModule({
+        imports: [
+          ObjectionCoreModule.forRoot({
+            config
+          })
+        ]
+      }).compile();
+    });
+
+    test("provides a connection", () => {
+      const connection = testingModule.get<knex>("KnexConnection");
+
+      expect(connection).toBeDefined();
+    });
+
+    test("provides a base model", () => {
+      const model = testingModule.get<Model>("ObjectionBaseModel");
+
+      expect(model).toBeDefined();
+    });
+  });
+
+  describe("#forRootAsync", () => {
+    beforeEach(async () => {
+      testingModule = await Test.createTestingModule({
+        imports: [
+          ObjectionCoreModule.forRootAsync({
+            useFactory() {
+              return {
+                config
+              };
+            }
+          })
+        ]
+      }).compile();
+    });
+
+    test("provides a connection", () => {
+      const connection = testingModule.get<knex>(KNEX_CONNECTION);
+
+      expect(connection).toBeDefined();
+    });
+
+    test("provides a base model", () => {
+      const model = testingModule.get<Model>(OBJECTION_BASE_MODEL);
+
+      expect(model).toBeDefined();
+    });
+  });
+
+  describe("#createAsyncProviders", () => {
+    class ModuleOptionsFactory implements ObjectionModuleOptionsFactory {
+      public createObjectionModuleOptions(): ObjectionModuleOptions {
+        return {
+          config
+        };
+      }
+    }
+
+    test("throws an error if options.useClass, useExisting, useFactory are not provided", () => {
+      expect(() => {
+        ObjectionCoreModule.createAsyncProviders({});
+      }).toThrowError("Invalid configuration");
+    });
+
+    test("leverages useClass if provided", () => {
+      const providers = ObjectionCoreModule.createAsyncProviders({
+        useClass: ModuleOptionsFactory
+      });
+
+      expect(providers).toEqual([
+        {
+          inject: [ModuleOptionsFactory],
+          useFactory: expect.any(Function),
+          provide: OBJECTION_MODULE_OPTIONS
+        },
+        {
+          useClass: ModuleOptionsFactory,
+          provide: ModuleOptionsFactory
+        }
+      ]);
+    });
+
+    test("returns an array of providers when useExisting is passed", () => {
+      const providers = ObjectionCoreModule.createAsyncProviders({
+        useExisting: ModuleOptionsFactory
+      });
+
+      expect(providers).toEqual([
+        {
+          inject: [ModuleOptionsFactory],
+          useFactory: expect.any(Function),
+          provide: OBJECTION_MODULE_OPTIONS
+        }
+      ]);
+    });
+
+    test("returns an array of providers when useFactory is passed", () => {
+      const providers = ObjectionCoreModule.createAsyncProviders({
+        useFactory: () => ({
+          config
+        })
+      });
+
+      expect(providers).toEqual([
+        {
+          inject: [],
+          useFactory: expect.any(Function),
+          provide: OBJECTION_MODULE_OPTIONS
+        }
+      ]);
+    });
+  });
+
+  describe("#createAsyncOptionsProvider", () => {
+    // eslint-disable-next-line new-cap
+    @Injectable()
+    class ModuleOptionsFactory implements ObjectionModuleOptionsFactory {
+      public createObjectionModuleOptions(): ObjectionModuleOptions {
+        return {
+          config
+        };
+      }
+    }
+
+    test("returns the appropriate provider when useFactory is passed", () => {
+      const provider = ObjectionCoreModule.createAsyncOptionsProvider({
+        useFactory: () => ({
+          config
+        })
+      });
+
+      expect(provider).toEqual({
+        inject: [],
+        provide: OBJECTION_MODULE_OPTIONS,
+        useFactory: expect.any(Function)
+      });
+    });
+
+    test("returns the appropriate provider when useExisting is passed", () => {
+      const provider = ObjectionCoreModule.createAsyncOptionsProvider({
+        useExisting: ModuleOptionsFactory
+      });
+
+      expect(provider).toEqual({
+        inject: [ModuleOptionsFactory],
+        provide: OBJECTION_MODULE_OPTIONS,
+        useFactory: expect.any(Function)
+      });
+    });
+
+    test("returns an async factory function that calls createObjectionModuleOptions", async () => {
+      jest.spyOn(
+        ModuleOptionsFactory.prototype,
+        "createObjectionModuleOptions"
+      );
+
+      await Test.createTestingModule({
+        imports: [
+          ObjectionCoreModule.forRootAsync({
+            useClass: ModuleOptionsFactory
+          })
+        ]
+      }).compile();
+
+      expect(
+        ModuleOptionsFactory.prototype.createObjectionModuleOptions
+      ).toHaveBeenCalled();
+    });
+  });
+});
diff --git a/tests/module.spec.ts b/tests/module.spec.ts
index 6454e3ca..4a939f0b 100644
--- a/tests/module.spec.ts
+++ b/tests/module.spec.ts
@@ -1,3 +1,4 @@
+import { KNEX_CONNECTION, OBJECTION_BASE_MODEL } from "@/constants";
 import { ObjectionModule } from "@/module";
 import { Test, TestingModule } from "@nestjs/testing";
 import knex from "knex";
@@ -25,13 +26,13 @@ describe("ObjectionModule", () => {
     });
 
     test("provides a connection", () => {
-      const connection = testingModule.get<knex>("KnexConnection");
+      const connection = testingModule.get<knex>(KNEX_CONNECTION);
 
       expect(connection).toBeDefined();
     });
 
     test("provides a base model", () => {
-      const model = testingModule.get<Model>("ObjectionBaseModel");
+      const model = testingModule.get<Model>(OBJECTION_BASE_MODEL);
 
       expect(model).toBeDefined();
     });