ts-mockito

repository·master·Indexed 21 days ago

https://github.com/nagrock/ts-mockito

A strongly typed mocking library for TypeScript version 2.6.0, inspired by Mockito. It provides tools for creating mocks of classes, interfaces, and abstract classes, spying on real objects, stubbing behaviors using when().thenReturn(), and verifying method calls with flexible argument matchers and call count assertions.

Tokens
5.1K
Snippets
25
Records
28
Agent score
66%

What's inside ts-mockito

  1. Create and use a mock

    master

    To create a mock, use the mock() function with the class or type you want to mock. To get a usable instance of that mock to pass into your application code, use the instance() function. This allows you to control the behavior of the object and verify how it is used.

    // Creating mock
    let mockedFoo:Foo = mock(Foo);
    
    // Getting instance from mock
    let foo:Foo = instance(mockedFoo);
    
    // Using instance in source code
    foo.getBar(3);
    foo.getBar(5);
    
    // Explicit, readable verification
    verify(mockedFoo.getBar(3)).called();
    verify(mockedFoo.getBar(anything())).called();
  2. Capture method arguments

    master

    Use capture() to inspect the arguments passed to a mocked method. You can retrieve specific calls using methods like .last(), .first(), .second(), or .byCallIndex(n).

    let mockedFoo:Foo = mock(Foo);
    let foo:Foo = instance(mockedFoo);
    
    // Call method
    foo.sumTwoNumbers(1, 2);
    
    // Check first arg captor values
    const [firstArg, secondArg] = capture(mockedFoo.sumTwoNumbers).last();
    console.log(firstArg);    // prints 1
    console.log(secondArg);    // prints 2
  3. Mock interfaces, abstract classes, and generics

    master

    Mocking Interfaces

    To mock an interface, pass the interface type as a generic to the mock<T>() function. This requires a Proxy implementation.

    Mocking Abstract Classes

    Abstract classes can be mocked just like regular classes using mock(AbstractClass).

    Mocking Generic Classes

    Generic classes can be mocked by providing the generic type in the mock definition.

    // Interface
    let mockedFoo:FooInterface = mock<FooInterface>();
    
    // Abstract Class
    const mockedFoo: SampleAbstractClass = mock(SampleAbstractClass);
    
    // Generic Class
    const mockedFoo: SampleGeneric<SampleInterface> = mock(SampleGeneric);
  4. Stub method calls with `when().thenReturn()`

    master

    Use when() combined with thenReturn() to define what a mocked method should return when called with specific arguments. If a method is called with arguments that were not stubbed, it will return null by default.

    // Creating mock
    let mockedFoo:Foo = mock(Foo);
    
    // stub method before execution
    when(mockedFoo.getBar(3)).thenReturn('three');
    
    // Getting instance
    let foo:Foo = instance(mockedFoo);
    
    // prints three
    console.log(foo.getBar(3));
    
    // prints null, because "getBar(999)" was not stubbed
    console.log(foo.getBar(999));
  5. Stub methods to throw errors

    master

    Use thenThrow() to make a mocked method throw an error when called.

    let mockedFoo:Foo = mock(Foo);
    
    when(mockedFoo.getBar(10)).thenThrow(new Error('fatal error'));
    
    let foo:Foo = instance(mockedFoo);
    try {
        foo.getBar(10);
    } catch (error:Error) {
        console.log(error.message); // 'fatal error'
    }
  6. Verify call order

    master

    You can verify the relative order of calls between different mocks using calledBefore() and calledAfter().

    let mockedFoo:Foo = mock(Foo);
    let mockedBar:Bar = mock(Bar);
    
    // Getting instance
    let foo:Foo = instance(mockedFoo);
    let bar:Bar = instance(mockedBar);
    
    // Some calls
    foo.getBar(1);
    bar.getFoo(2);
    
    // Call order verification
    verify(mockedFoo.getBar(1)).calledBefore(mockedBar.getFoo(2));    // foo.getBar(1) has been called before bar.getFoo(2)
    verify(mockedBar.getFoo(2)).calledAfter(mockedFoo.getBar(1));    // bar.getFoo(2) has been called before foo.getBar(1)
  7. Stub methods with custom implementations

    master

    Use thenCall() to provide a custom function implementation for a mocked method. This allows you to execute logic based on the arguments passed to the call.

    let mockedFoo:Foo = mock(Foo);
    let foo:Foo = instance(mockedFoo);
    
    when(mockedFoo.sumTwoNumbers(anyNumber(), anyNumber())).thenCall((arg1:number, arg2:number) => {
        return arg1 * arg2; 
    });
    
    // prints '50' because we've changed sum method implementation to multiply!
    console.log(foo.sumTwoNumbers(5, 10));
  8. Reset mock calls and stubs

    master

    You can reset parts of a mock's state:

    • resetCalls(mock): Resets only the call counters (verification state). The stubs remain intact.
    • reset(mock): Resets both the call counters and all defined stubs.
    // Reset just mock call counter
    resetCalls(mockedFoo);
    
    // Reset mock call counter AND all stubs
    reset(mockedFoo);
  9. Verify call counts

    master

    Use verify() to check how many times a method was called with specific arguments. You can use various matchers like anything(), anyNumber(), or between() to make comparisons more flexible. Common call count matchers include:

    • .once(): exactly once
    • .twice(): exactly twice
    • .thrice(): exactly three times
    • .times(n): exactly $n$ times
    • .atLeast(n): minimum $n$ times
    • .atMost(n): maximum $n$ times
    • .never(): zero times
    // Creating mock
    let mockedFoo:Foo = mock(Foo);
    let foo:Foo = instance(mockedFoo);
    
    // Some calls
    foo.getBar(1);
    foo.getBar(2);
    foo.getBar(2);
    foo.getBar(3);
    
    // Call count verification
    verify(mockedFoo.getBar(1)).once();               // was called with arg === 1 only once
    verify(mockedFoo.getBar(2)).twice();              // was called with arg === 2 exactly two times
    verify(mockedFoo.getBar(between(2, 3))).thrice(); // was called with arg between 2-3 exactly three times
    verify(mockedFoo.getBar(anyNumber()).times(4);    // was called with any number arg exactly four times
    verify(mockedFoo.getBar(2)).atLeast(2);           // was called with arg === 2 min two times
    verify(mockedFoo.getBar(anything())).atMost(4);   // was called with any argument max four times
    verify(mockedFoo.getBar(4)).never();              // was never called with arg === 4
  10. Record multiple behaviors for the same call

    master

    You can chain multiple thenReturn() calls to return different values sequentially for the same matching arguments. The last defined behavior will be repeated infinitely once the sequence is exhausted.

    You can also use the shorthand syntax by passing multiple arguments to a single thenReturn() call.

    // Chained syntax
    when(mockedFoo.getBar(anyNumber())).thenReturn('one').thenReturn('two').thenReturn('three');
    
    // Shorthand syntax
    when(mockedFoo.getBar(anyNumber())).thenReturn('one', 'two', 'three');
  11. Stub getter and property values

    master

    You can stub getter values using the same when().thenReturn() syntax used for methods. This also works for properties that do not have explicit getters, provided that an ES6 Proxy is available in your environment.

    // Creating mock
    let mockedFoo:Foo = mock(Foo);
    
    // stub getter before execution
    when(mockedFoo.sampleGetter).thenReturn('three');
    
    // Getting instance
    let foo:Foo = instance(mockedFoo);
    
    // prints three
    console.log(foo.sampleGetter);