Let's create a mock server that emulates responses for requests to three paths to a routing microservice: /signin, /signup, and /comments. There is the mockito crate that provides a server for emulating HTTP responses. We will use the example from Chapter 11, Involving Concurrency with Actors and the Actix Crate. Copy it and add these extra dependencies:
mockito = "0.15"
reqwest = "0.9"
We need the mockito crate to start a server with mocks, and the reqwest crate to make HTTP requests to our Actix server instance.
Create a tests module with the #[cfg(test)] attribute that will be compiled for testing only, and import the following types that we will use for testing:
use crate::{start, Comment, LinksMap, UserForm, UserId};
use lazy_static::lazy_static;
use mockito::{mock, Mock};
use reqwest::Client;
use serde::{Deserialize, Serialize};
use std::sync::Mutex;
use std::time::Duration;
use std::thread;
We use types of router microservices to prepare requests; namely, Comment, UserForm, and UserId. Also, we added the LinksMap struct to configure URLs to mocks:
#[derive(Clone)]
struct LinksMap {
signup: String,
signin: String,
new_comment: String,
comments: String,
}
Add this struct to State and use it with handlers to get the URLs of microservices:
#[derive(Clone)]
struct State {
counter: RefCell<i64>,
links: LinksMap,
}
Also, we imported the lazy_static! macro that we need to initialize a Mutex, which we will use to check that the Actix Server started once. Rust also has the Once type, which can also be used, but we need to wait a certain interval before letting the services perform requests, and the is_completed method of Once type is unstable. To create mocks, we will use the mock function of the mockito crate and a Mock type that represents a handler of a specific request.
Create a function to add mocks, as follows:
fn add_mock<T>(method: &str, path: &str, result: T) -> Mock
where
T: Serialize,
{
mock(method, path)
.with_status(200)
.with_header("Content-Type", "application/json")
.with_body(serde_json::to_string(&result).unwrap())
.create()
}
The add_mock function expects an HTTP method and path to emulated resource. Also, it takes a value returned as a response in JSON format.
We call the mock function to create a Mock instance and tune it with the following methods:
- with_status sets the status code of a response
- with_header sets a specific value for a header
- with_body sets the body of a response
Finally, we call the crate method, which tries to start a mock server and attach our created Mock to it. Now, we can start a router microservice instance and prepare all the necessary mocks to emulate other microservices that the router expects.