Skip to content

Mocking endpoints

TypedRest endpoint classes implement interfaces, making them straightforward to mock with standard testing frameworks. This allows you to test service or business logic that depends on TypedRest endpoints without making any HTTP calls.

Example service

Consider a service that filters contacts via a TypedRest endpoint:

class ContactService(ICollectionEndpoint<Contact> contacts)
{
    public async Task<List<Contact>> GetActiveContactsAsync(CancellationToken ct = default)
        => (await contacts.ReadAllAsync(ct))
            .Where(c => c.IsActive)
            .ToList();
}
class ContactService {
    private final CollectionEndpoint<Contact> contacts;

    ContactService(CollectionEndpoint<Contact> contacts) {
        this.contacts = contacts;
    }

    List<Contact> getActiveContacts() {
        return contacts.readAll().stream()
            .filter(Contact::isActive)
            .collect(Collectors.toList());
    }
}
class ContactService(private val contacts: CollectionEndpoint<Contact>) {
    fun getActiveContacts(): List<Contact> =
        contacts.readAll().filter { it.isActive }
}
class ContactService {
    constructor(private contacts: CollectionEndpoint<Contact>) {}

    async getActiveContacts(): Promise<Contact[]> {
        return (await this.contacts.readAll()).filter(c => c.isActive);
    }
}

Unit tests with mocks

Use Moq (or any other mocking library) to substitute the endpoint interface:

var mockContacts = new Mock<ICollectionEndpoint<Contact>>();
mockContacts
    .Setup(c => c.ReadAllAsync(It.IsAny<CancellationToken>()))
    .ReturnsAsync([
        new Contact { Name = "Alice", IsActive = true },
        new Contact { Name = "Bob",   IsActive = false }
    ]);

var service = new ContactService(mockContacts.Object);
var result = await service.GetActiveContactsAsync();

result.Should().ContainSingle(c => c.Name == "Alice");

Key interfaces available for mocking:

Interface Description
IElementEndpoint<T> Single resource (ReadAsync, SetAsync, DeleteAsync, …)
ICollectionEndpoint<T> Resource collection (ReadAllAsync, CreateAsync, …)
IActionEndpoint Parameterless RPC trigger
IConsumerEndpoint<T> RPC call that accepts input
IFunctionEndpoint<TIn, TOut> RPC call with input and output
IProducerEndpoint<T> RPC call that returns a result

Use Mockito (or any other mocking library) to substitute the endpoint interface:

CollectionEndpoint<Contact> mockContacts = mock(CollectionEndpoint.class);
when(mockContacts.readAll()).thenReturn(List.of(
    new Contact("Alice", true),
    new Contact("Bob",   false)
));

ContactService service = new ContactService(mockContacts);
List<Contact> result = service.getActiveContacts();

assertEquals(1, result.size());
assertEquals("Alice", result.get(0).getName());

Key interfaces available for mocking:

Interface Description
ElementEndpoint<T> Single resource (read, set, delete, …)
CollectionEndpoint<T> Resource collection (readAll, create, …)
ActionEndpoint Parameterless RPC trigger
ConsumerEndpoint<T> RPC call that accepts input
FunctionEndpoint<TIn, TOut> RPC call with input and output
ProducerEndpoint<T> RPC call that returns a result

Use mockito-kotlin (or any other mocking library) to substitute the endpoint interface:

val mockContacts = mock<CollectionEndpoint<Contact>>()
whenever(mockContacts.readAll()).thenReturn(listOf(
    Contact("Alice", isActive = true),
    Contact("Bob",   isActive = false)
))

val service = ContactService(mockContacts)
val result = service.getActiveContacts()

assertEquals(listOf(Contact("Alice", isActive = true)), result)

Key interfaces available for mocking:

Interface Description
ElementEndpoint<T> Single resource (read, set, delete, …)
CollectionEndpoint<T> Resource collection (readAll, create, …)
ActionEndpoint Parameterless RPC trigger
ConsumerEndpoint<T> RPC call that accepts input
FunctionEndpoint<TIn, TOut> RPC call with input and output
ProducerEndpoint<T> RPC call that returns a result

Use Jest's built-in mock utilities (or any other mocking library) to create a partial stand-in for the endpoint:

const mockContacts = {
    readAll: jest.fn().mockResolvedValue([
        { name: 'Alice', isActive: true },
        { name: 'Bob',   isActive: false }
    ])
} as unknown as CollectionEndpoint<Contact>;

const service = new ContactService(mockContacts);
const result = await service.getActiveContacts();

expect(result).toEqual([{ name: 'Alice', isActive: true }]);

Because TypeScript uses structural typing, any object that provides the methods your service calls is a valid substitute - no separate interface declaration is required.