All Projects → udibo → mock

udibo / mock

Licence: MIT license
Utilities to help mock behavior, spy on function calls, stub methods, and fake time for tests.

Programming Languages

typescript
32286 projects

Projects that are alternatives of or similar to mock

mocka
Mocka - The complete testing framework for LUA and Nginx
Stars: ✭ 26 (-16.13%)
Mutual labels:  mock, stub, spy
phake
PHP Mocking Framework
Stars: ✭ 464 (+1396.77%)
Mutual labels:  mock, stub, spy
Mockery
Mockery is a simple yet flexible PHP mock object framework for use in unit testing with PHPUnit, PHPSpec or any other testing framework. Its core goal is to offer a test double framework with a succinct API capable of clearly defining all possible object operations and interactions using a human readable Domain Specific Language (DSL).
Stars: ✭ 10,048 (+32312.9%)
Mutual labels:  mock, stub
Spy
Clojure/ClojureScript library for stubs, spies and mocks.
Stars: ✭ 131 (+322.58%)
Mutual labels:  mock, stub
Mockingbird
Simplify software testing, by easily mocking any system using HTTP/HTTPS, allowing a team to test and develop against a service that is not complete or is unstable or just to reproduce planned/edge cases.
Stars: ✭ 149 (+380.65%)
Mutual labels:  mock, stub
Cuckoo
Boilerplate-free mocking framework for Swift!
Stars: ✭ 1,344 (+4235.48%)
Mutual labels:  mock, stub
Impersonator
Ruby library to record and replay object interactions
Stars: ✭ 100 (+222.58%)
Mutual labels:  mock, stub
Mockit
A tool to quickly mock out end points, setup delays and more...
Stars: ✭ 1,534 (+4848.39%)
Mutual labels:  mock, stub
ts-mock-imports
Intuitive mocking library for Typescript class imports
Stars: ✭ 103 (+232.26%)
Mutual labels:  mock, stub
spydriver
🕵️ Lightweight utility to intercept WebDriver and WebElement method calls.
Stars: ✭ 24 (-22.58%)
Mutual labels:  mock, spy
sinon-mongoose
Extend Sinon stubs for Mongoose methods to test chained methods easily
Stars: ✭ 87 (+180.65%)
Mutual labels:  mock, stub
Timex
A test-friendly replacement for golang's time package
Stars: ✭ 53 (+70.97%)
Mutual labels:  mock, stub
Mocha
Mocha is a mocking and stubbing library for Ruby
Stars: ✭ 1,065 (+3335.48%)
Mutual labels:  mock, stub
Mimic
A mocking library for Elixir
Stars: ✭ 104 (+235.48%)
Mutual labels:  mock, stub
Wiremockui
Wiremock UI - Tool for creating mock servers, proxies servers and proxies servers with the option to save the data traffic from an existing API or Site.
Stars: ✭ 38 (+22.58%)
Mutual labels:  mock, stub
Dyson
Node server for dynamic, fake JSON.
Stars: ✭ 814 (+2525.81%)
Mutual labels:  mock, stub
Rubicon
Swift parser + mock generator
Stars: ✭ 42 (+35.48%)
Mutual labels:  mock, spy
Swiftmockgeneratorforxcode
An Xcode extension (plugin) to generate Swift test doubles automatically.
Stars: ✭ 522 (+1583.87%)
Mutual labels:  mock, stub
Ohhttpstubs
Stub your network requests easily! Test your apps with fake network data and custom response time, response code and headers!
Stars: ✭ 4,831 (+15483.87%)
Mutual labels:  mock, stub
aem-stubs
Tool for providing sample data for AEM applications in a simple and flexible way. Stubbing server on AEM, no separate needed.
Stars: ✭ 40 (+29.03%)
Mutual labels:  mock, stub

Mock

release deno doc CI codecov license

Utilities to help mock behavior, spy on function calls, stub methods and fake time for tests.

This module is being archived. It has been added to Deno's standard library in the testing directory. Use Deno's standard library instead.

Features

  • Spy on functions and instance methods to record information about calls
  • Stub methods to simulate behavior and record information about calls
  • Fake time for testing time sensitive logic

Installation

This is an ES Module written in TypeScript and can be used in Deno projects. ES Modules are the official standard format to package JavaScript code for reuse. A JavaScript bundle is provided with each release so that it can be used in Node.js packages or web browsers.

Deno

To include it in a Deno project, you can import directly from the TS files. This module is available in Deno's third part module registry but can also be imported directly from GitHub using raw content URLs.

// Import from Deno's third party module registry
import { spy, stub } from "https://deno.land/x/[email protected]/mod.ts";
// Import from GitHub
import { spy, stub } "https://raw.githubusercontent.com/udibo/mock/0.15.2/mod.ts";

If you do not need all of the sub-modules, you can choose to just import the sub-modules you need.

// Import from Deno's third party module registry
import { spy, stub } from "https://deno.land/x/[email protected]/mock.ts";
// Import from GitHub
import {
  spy,
  stub,
} from "https://raw.githubusercontent.com/udibo/mock/0.15.2/mock.ts";

Sub-modules

mock.ts module is for spying on functions and instance methods with or without changing behavior.

time.ts module is for controlling the Date object and timers.

callbacks.ts module contains a set of functions you may want to use when stubbing instance methods.

asserts.ts module contains a set of functions for making assertions about calls to spys and stubs.

Node.js

Node.js fully supports ES Modules.

If a Node.js package has the type "module" specified in its package.json file, the JavaScript bundle can be imported as a .js file.

import { spy, stub } from "./mock_0.15.2.js";

The default type for Node.js packages is "commonjs". To import the bundle into a commonjs package, the file extension of the JavaScript bundle must be changed from .js to .mjs.

import { spy, stub } from "./mock_0.15.2.mjs";

See Node.js Documentation for more information.

Browser

Most modern browsers support ES Modules.

The JavaScript bundle can be imported into ES modules. Script tags for ES modules must have the type attribute set to "module".

<script type="module" src="main.js"></script>
// main.js
import { spy, stub } from "./mock_0.15.2.js";

You can also embed a module script directly into an HTML file by placing the JavaScript code within the body of the script tag.

<script type="module">
  import { spy, stub } from "./mock_0.15.2.js";
</script>

See MDN Documentation for more information.

Usage

Below are some examples of how to use Spys, Stubs, and FakeTime in tests. When spying/stubing instance methods, you should wrap the calls and expectations with a try block then restore the function in a finally block to ensure the original instance method is restored before continuing to other tests. The same applies when using fake time.

See deno docs for more information.

Spy

When spying on a function or instance method, all arguments and return values are recorded but the behavior of that function is unchanged. This gives you the ability to verify that the code you are testing calls functions it depends on correctly and that they return the responses you expect them to.

If you have a function that takes a callback but you don't need it to do anything, you can create an empty spy. An empty spy will just return undefined for any calls made to it.

import { assertEquals } from "https://deno.land/[email protected]/testing/asserts.ts";
import { assertSpyCall, spy } from "https://deno.land/x/[email protected]/mod.ts";

function add(
  a: number,
  b: number,
  callback: (error: Error | void, value?: number) => void,
): void {
  const value: number = a + b;
  if (typeof value === "number" && !isNaN(value)) callback(undefined, value);
  else callback(new Error("invalid input"));
}

Deno.test("add calls fake callback", () => {
  const callback = spy();

  assertEquals(add(2, 3, callback), undefined);
  assertSpyCall(callback, 0, { args: [undefined, 5] });
  assertEquals(add(5, 4, callback), undefined);
  assertSpyCall(callback, 1, { args: [undefined, 9] });
});

If you have a function that takes a callback that needs to still behave normally, you can wrap it with a spy.

import { assertEquals } from "https://deno.land/[email protected]/testing/asserts.ts";
import {
  assertSpyCall,
  assertSpyCalls,
  spy,
} from "https://deno.land/x/[email protected]/mod.ts";

function filter<T>(values: T[], callback: (value: T) => boolean): any[] {
  return values.filter(callback);
}

function isEven(value: number): boolean {
  return value % 2 === 0;
}

Deno.test("filter calls real callback", () => {
  const callback = spy(isEven);
  const values: number[] = [5, 6, 7, 8];

  assertEquals(filter(values, callback), [6, 8]);
  assertSpyCall(callback, 0, { args: [5, 0, values], returned: false });
  assertSpyCall(callback, 1, { args: [6, 1, values], returned: true });
  assertSpyCall(callback, 2, { args: [7, 2, values], returned: false });
  assertSpyCall(callback, 3, { args: [8, 3, values], returned: true });
  assertSpyCalls(callback, 4);
});

If you have an instance method that needs to still behave normally, you can wrap it with a spy. When you are done spying on a method, you need to call the restore function on the spy object to remove the wrapper from the instance method. If it is not restored and you attempt to wrap it again, it will throw a spy error saying "already spying on function".

import { assertEquals } from "https://deno.land/[email protected]/testing/asserts.ts";
import {
  assertSpyCall,
  assertSpyCalls,
  spy,
} from "https://deno.land/x/[email protected]/mod.ts";

class Database {
  // deno-lint-ignore no-explicit-any
  private queries: any;
  constructor() {
    this.queries = {
      "select id, first_name from USERS where last_name=?": {
        "Doe": [[1, "Jane"], [2, "John"]],
        "Smith": [[3, "Jane"]],
      },
      "select id, last_name from USERS where first_name=?": {
        "Jane": [[1, "Doe"], [3, "Smith"]],
        "John": [[2, "Doe"]],
      },
    };
  }

  // deno-lint-ignore no-explicit-any
  query(query: string, params: any[]): any[][] {
    return this.queries[query][params[0]]; // implementation not important for example
  }
}

function getNamesByFirstName(db: Database, firstName: string): string[] {
  return db
    .query(
      "select id, last_name from USERS where first_name=?",
      [firstName],
    )
    .map((row) => `${firstName} ${row[1]}`);
}

function getNamesByLastName(db: Database, lastName: string): string[] {
  return db
    .query(
      "select id, first_name from USERS where last_name=?",
      [lastName],
    )
    .map((row) => `${row[1]} ${lastName}`);
}

Deno.test("functions call db.query", () => {
  const db = new Database();
  const query = spy(db, "query");

  assertEquals(getNamesByFirstName(db, "Jane"), ["Jane Doe", "Jane Smith"]);
  assertSpyCall(query, 0, {
    args: ["select id, last_name from USERS where first_name=?", ["Jane"]],
    self: db,
    returned: [[1, "Doe"], [3, "Smith"]],
  });
  assertEquals(getNamesByLastName(db, "Doe"), ["Jane Doe", "John Doe"]);
  assertSpyCall(query, 1, {
    args: ["select id, first_name from USERS where last_name=?", ["Doe"]],
    self: db,
    returned: [[1, "Jane"], [2, "John"]],
  });
  assertEquals(getNamesByFirstName(db, "John"), ["John Doe"]);
  assertSpyCall(query, 2, {
    args: ["select id, last_name from USERS where first_name=?", ["John"]],
    self: db,
    returned: [[2, "Doe"]],
  });
  assertEquals(getNamesByLastName(db, "Smith"), ["Jane Smith"]);
  assertSpyCall(query, 3, {
    args: ["select id, first_name from USERS where last_name=?", ["Smith"]],
    self: db,
    returned: [[3, "Jane"]],
  });
  assertSpyCalls(query, 4);
});

Stub

When stubbing an instance method, all arguments and return values are recorded but the behavior of that instance method is fake. This gives you the ability to verify that the code you are testing calls an instance method and that it handles the expected behavior correctly.

If you have an instance method but you don't need it to do or return anything, you can create an empty stub. An empty stub will just return undefined for any calls made to it.

import { assertEquals } from "https://deno.land/[email protected]/testing/asserts.ts";
import {
  assertSpyCall,
  assertSpyCalls,
  stub,
} from "https://deno.land/x/[email protected]/mod.ts";

class Cat {
  action(name: string): any {
    throw new Error("unimplemented");
  }
}

function doAction(cat: Cat, action: string): any {
  return cat.action(action);
}

Deno.test("doAction", () => {
  const cat = new Cat();
  const action = stub(cat, "action");

  assertEquals(doAction(cat, "walk"), undefined);
  assertSpyCall(action, 0, {
    self: cat,
    args: ["walk"],
    returned: undefined,
  });

  assertEquals(doAction(cat, "jump"), undefined);
  assertSpyCall(action, 1, {
    self: cat,
    args: ["jump"],
    returned: undefined,
  });

  assertSpyCalls(action, 2);
});

If you have an instance method but need it to return specific values for each call, you can create a stub with a function that returns those values. The stub function will have all the same arguments available to it if you would like to generate return values based on the arguments.

A callback helper is provided for converting an iterable into a callback for your stub function. You can add more return values after initialization by pushing onto the array as long as the iterator has not completed. An iterator is considered complete if called after all values have been returned. The callback will return undefined to each call after the iterator is done.

import { assertEquals } from "https://deno.land/[email protected]/testing/asserts.ts";
import {
  assertSpyCallAsync,
  assertSpyCalls,
  resolvesNext,
  stub,
} from "https://deno.land/x/[email protected]/mod.ts";

class Database {
  query(_query: string, _params: unknown[]): Promise<unknown[][]> {
    throw new Error("unimplemented");
  }
}

async function getUsers(
  db: Database,
  lastName: string,
  firstName?: string,
): Promise<string[]> {
  return (await db
    .query(
      "SELECT id, username FROM users WHERE last_name=?" +
        (firstName ? " and first_name=?" : ""),
      firstName ? [lastName, firstName] : [lastName],
    ))
    .map((row) => `${row[0]} ${row[1]}`);
}

Deno.test("getUsers", async () => {
  const db = new Database();
  const resolves: [number, string][][] = [
    [[1, "jd"], [2, "johnd"], [3, "janedoe"]],
    [[2, "johnd"]],
  ];
  const query = stub(db, "query", resolvesNext(resolves));

  try {
    assertEquals(await getUsers(db, "doe"), ["1 jd", "2 johnd", "3 janedoe"]);
    assertEquals(await getUsers(db, "doe", "john"), ["2 johnd"]);

    resolves.push([[3, "janedoe"]]);
    assertEquals(await getUsers(db, "doe"), ["3 janedoe"]);

    await assertSpyCallAsync(query, 0, {
      args: [
        "SELECT id, username FROM users WHERE last_name=?",
        ["doe"],
      ],
      self: db,
      returned: [[1, "jd"], [2, "johnd"], [3, "janedoe"]],
    });

    await assertSpyCallAsync(query, 1, {
      args: [
        "SELECT id, username FROM users WHERE last_name=? and first_name=?",
        ["doe", "john"],
      ],
      self: db,
      returned: [[2, "johnd"]],
    });

    await assertSpyCallAsync(query, 2, {
      args: [
        "SELECT id, username FROM users WHERE last_name=?",
        ["doe"],
      ],
      self: db,
      returned: [[3, "janedoe"]],
    });

    assertSpyCalls(query, 3);
  } finally {
    query.restore();
  }
});

FakeTime

Overrides the real Date object and timer functions with fake ones that can be controlled through the fake time instance.

import {
  assertSpyCalls,
  FakeTime,
  Spy,
  spy,
} from "https://deno.land/x/[email protected]/mod.ts";

function secondInterval(cb: () => void): void {
  setInterval(cb, 1000);
}

Deno.test("secondInterval calls callback every second", () => {
  const time = new FakeTime();
  const cb = spy();

  try {
    secondInterval(cb);
    assertSpyCalls(cb, 0);
    time.tick(500);
    assertSpyCalls(cb, 0);
    time.tick(500);
    assertSpyCalls(cb, 1);
    time.tick(3500);
    assertSpyCalls(cb, 4);
  } finally {
    time.restore();
  }
});

License

MIT

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].