All Projects → tank-bohr → bookish_spork

tank-bohr / bookish_spork

Licence: Apache-2.0 license
Erlang library for testing http requests

Programming Languages

erlang
1774 projects
Makefile
30231 projects
shell
77523 projects

Projects that are alternatives of or similar to bookish spork

mockcpp
Two C/C++ testing tools, mockcpp and testngpp.
Stars: ✭ 40 (-51.22%)
Mutual labels:  testing-tools
heartbeat
A service to keep a live heartbeat (ping) on multiple devices
Stars: ✭ 27 (-67.07%)
Mutual labels:  webserver
phpkoa
PHP异步编程: 基于 PHP 实(chao)现(xi) NODEJS web框架 KOA。
Stars: ✭ 52 (-36.59%)
Mutual labels:  webserver
tressa
Little test utility
Stars: ✭ 18 (-78.05%)
Mutual labels:  testing-tools
php.autotest
autotest for php written in php
Stars: ✭ 19 (-76.83%)
Mutual labels:  testing-tools
effcee
Effcee is a C++ library for stateful pattern matching of strings, inspired by LLVM's FileCheck
Stars: ✭ 76 (-7.32%)
Mutual labels:  testing-tools
merlin
Testing and Benchmarking framework for deno 🧙‍♂️
Stars: ✭ 46 (-43.9%)
Mutual labels:  testing-tools
vPAV
viadee Process Application Validator
Stars: ✭ 47 (-42.68%)
Mutual labels:  testing-tools
laika
Log, test, intercept and modify Apollo Client's operations
Stars: ✭ 99 (+20.73%)
Mutual labels:  testing-tools
client-java
Asynchronous client for Java-based agents
Stars: ✭ 17 (-79.27%)
Mutual labels:  testing-tools
embedio-extras
Additional Modules showing how to extend EmbedIO.
Stars: ✭ 43 (-47.56%)
Mutual labels:  webserver
toradocu
Toradocu - automated generation of test oracles from Javadoc documentation
Stars: ✭ 39 (-52.44%)
Mutual labels:  testing-tools
test-real-styles
(test-)framework agnostic utilities to test real styling of (virtual) dom elements
Stars: ✭ 37 (-54.88%)
Mutual labels:  testing-tools
initial-webserver-setup
Ansible playbook for initial ubuntu 16.04 webserver setup and Laravel zero time deployment
Stars: ✭ 50 (-39.02%)
Mutual labels:  webserver
rpi-nginx
[DEPRECATED] NGINX on Raspberry Pi / ARM
Stars: ✭ 20 (-75.61%)
Mutual labels:  webserver
ctest
A simple portable C test runner
Stars: ✭ 17 (-79.27%)
Mutual labels:  testing-tools
CodeBaseManager
Multi-langage CLI tool to manage your code base
Stars: ✭ 11 (-86.59%)
Mutual labels:  testing-tools
go-test-report
Captures go test output and parses it into a single self-contained HTML file.
Stars: ✭ 68 (-17.07%)
Mutual labels:  testing-tools
Teapot
Teapot micro web framework for Pharo Smalltalk
Stars: ✭ 86 (+4.88%)
Mutual labels:  webserver
Orion-Stress-Tester
A simple, efficient and accurate stress tester, support HTTP, WebSocket and TCP
Stars: ✭ 32 (-60.98%)
Mutual labels:  testing-tools

Bookish spork

Copyright (c) 2018-2021 Alexey Nikitin

Version: 0.5.1

Authors: Alexey Nikitin ([email protected]) (web site: https://twitter.com/tank_bohr).

Logo

An erlang library to test http requests. Inspired by Ruby's WebMock.

Suitable for Elixir.

Erlang CI codecov Hex.pm Gitter

Rationale

There are several ways to test your http interaction

  • Real http request to real servers: not very reliable, requires internet
  • You can use external http server like https://httpbin.org/ (hackney approach)
  • You can mock your http client library
  • Also you can run an http-server within your application on your localhost on a particular port

The last approach is the best IMHO. It is absolutely http-client agnostic. It doesn't require internet connection or any external utilities.

bookish_spork provides you facilities to test your requests with real http server.

Usage

Bookish spork supports Erlang/OTP 20.3 or later.

First step: add to your rebar config

{profiles, [
    {test, [
        {deps, [
            {bookish_spork, "0.5.1"}
        ]}
    ]}
]}.

Second: start server in your tests.

bookish_spork:start_server().

It starts process without link. Thus you can use it in init_per_group and in init_per_suite callbacks. Default port is 32002 but you can specify any port you like with bookish_spork:start_server/1

Stub request

The simplest stub you can do is

bookish_spork:stub_request().

It will stub your requests with 204 No Content response with empty body.

If you need specify response you easily can do this:

bookish_spork:stub_request([Status, Headers, Content]).

Capture request

As usual the main goal is to test that you send the correct request

{ok, Request} = bookish_spork:capture_request().

It returns you an opaque structure of the request. You can inspect it with

Bypass comparison

An elixir library bypass does pretty much the same. And illustrates the same approach. It starts a cowboy web-server to replace a real service for test. It's a beautiful library with great API, documentation, and very concise source code. If you are an elixir developer, most likely, it will be a good fit for you.

But nevertheless bookish_spork has some advantages:

  • Bypass depends on cowboy and plug. Bookish spork has zero dependencies.
  • Bookish spork works seamlessly with both erlang and elixir. Bypass is supposed to be an elixir only library.
  • Bookish spork much simpler (I believe) (not any more).
  • Bookish spork allows you to inspect the request very deeply and accurate. For example take a look at bookish_spork_request:raw_headers/1 and bookish_spork_request:ssl_info/1 and bookish_spork_request:tls_ext/1. It can be useful for HTTP clients testing.

Elli comparison

Very often people use elli for this purpose. But elli is a full-featured web-server while bookish_spork is a testing library. It allows you to stub requests as close to your tests as possible. Without callback module and supervisor.

Examples

Setup and teardown

init_per_group(_GroupName, Config) ->
    {ok, _} = bookish_spork:start_server(),
    Config.

end_per_group(_GroupName, _Config) ->
    ok = bookish_spork:stop_server().

Set expectation

init_per_testcase(random_test, Config) ->
    bookish_spork:stub_request([200, #{}
        <<"{\"value\": \"Chuck Norris' favourite word: chunk.\"}">>]),
    Config.

Make assertions

random_test(_Config) ->
    ?assertEqual(<<"Chuck Norris' favourite word: chunk.">>, testee:make_request()),
    {ok, Request} = bookish_spork:capture_request(),
    ?assertEqual("/jokes/random", bookish_spork_request:uri(Request)).

As you can see there are two types of assertions:

  • we check a testee function result
  • we check a side effect: verifying outgoing request has correct attributes (uri in this case)
More complex expectations

There are cases when the testee function initiates more than one request. But if you know the order of your requests, you can set several expectations

bookish_spork:stub_request([200, #{}, <<"{\"value\": \"The first response\"}">>]),
bookish_spork:stub_request([200, #{}, <<"{\"value\": \"The second response\"}">>]).

The library will response in the order the stubs were defined.

Sometimes you can't guarantee the order of requests. Then you may stub request with the fun

bookish_spork:stub_request(fun(Request) ->
    case bookish_spork_request:uri(Request) of
        "/bookish/spork" ->
            [200, #{}, <<"Hello">>];
        "/admin/sporks" ->
            [403, #{}, <<"It is not possible here">>]
    end
end)

Module to work with request

Module to work with response

Stub multiple requests with one response

It can be useful to stub several requests with one command

bookish_spork:stub_request([200, #{<<"Content-Type" => "text/plan">>}, <<"Pants">>], _Times = 20)

The same with the fun

bookish_spork:stub_request(fun(Req) ->
    Body = bookish_spork_request:body(Req),
    [200, #{<<"X-Respond-With">> => <<"echo">>}, Body]
end, _Times = 150)

As you can see that it's not necessary to build response structure yourself. You can use handy three-element tuple or list syntax to define the response. But the bookish_spork_response:new/1 still works.

Elixir example
defmodule ChuckNorrisApiTest do
  use ExUnit.Case
  doctest ChuckNorrisApi

  setup do
    {:ok, _} = :bookish_spork.start_server()
    on_exit(fn -> :bookish_spork.stop_server() end)
  end

  test "retrieves a random joke" do
    :bookish_spork.stub_request([200, %{}, "{
      \"value\": \"Chuck norris tried to crank that soulja boy but it wouldn't crank up\"
    }"])
    assert ChuckNorrisApi.random == "Chuck norris tried to crank that soulja boy but it wouldn't crank up"

    {:ok, request} = :bookish_spork.capture_request()
    assert request.uri === "/jokes/random"
  end
end

For more details see examples dir.

Modules

bookish_spork
bookish_spork_acceptor
bookish_spork_acceptor_sup
bookish_spork_blocking_queue
bookish_spork_format
bookish_spork_handler
bookish_spork_request
bookish_spork_response
bookish_spork_server
bookish_spork_ssl
bookish_spork_tcp
bookish_spork_transport
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].