stripity-stripe
stripity-stripe copied to clipboard
Create a testing package
We should create a test "mock" system distributed as a separate package. This way, people can do the following:
[
{:stripity_stripe, "~> 2.0"},
{:stripity_stripe_testing, "~> 2.0", only: :test}
]
The test package can distribute a lightweight replica of the Stripe service. That way, testing can be done something like the following:
test "retrieves all plans where the storage limit is greater than 30" do
Stripe.Test.create(:plan, 10)
Stripe.Test.create(:plan, 10, metadata: [storage_limit: 10])
Stripe.Test.create(:plan, 10, metadata: [storage_limit: 35])
Stripe.Test.create(:plan, 10, metadata: [storage_limit: 30])
# This is business logic that will call the StripityStripe module
plans = MyApp.Module.get_plans(:gt, 30)
assert Enum.count(plans) == 10
end
The data can be stored on a per-test basis in ETS, allowing users to build up the necessary state and tear it down without needing to know the intricacies of the system.
For example:
defmodule Stripe.CustomerTest do
# this may be able to be true
use ExUnit.Case, async: false
# Most of this setup process can be abstracted into the library, but putting
# it here so that others understand
setup do
# Starts a separate process
# - That process loads a Plug responder that binds to an available port
# - It also seeds an ETS table that it claims ownership of
# - The ETS table and Plug responder are bound to this specific test,
# so they are isolated to this test and any state manipulation on them
# will not affect other tests
# - Returns a struct of some form like %Stripe.Test.Server{port: 4515, pid: #PID<0.35.0>}
{:ok, stripe_server} = Stripe.Test.Server.start()
Application.put_env(:stripity_stripe, :api_base_url, "http://localhost:#{stripe_server.port}")
on_exit fn ->
# Cleans up the ETS table and stops the plug responder and owning process
Stripe.Test.Server.stop(stripe_server)
end
{:ok, stripe: stripe_server}
end
describe "Stripe.Customer.retrieve/1" do
test "retrieves a customer by ID", %{stripe: stripe} do
# Uses the Stripe.Test.Customer module to create a new customer in the
# ETS backed server (essentially, this is a factory method)
%{id: id} = Stripe.Test.Customer.create(stripe)
# Makes an actual API request from the high level API through the low level
# API and through the OS network stack
{:ok, customer} = Stripe.Customer.retrieve(id)
assert customer.id == id
end
end
end
@joshsmith @begedin I started working on something, see here: https://github.com/whitepaperclip/stripe_mock
It starts an http server in your app's test env and tries to respond as accurately as possible to requests. Handles authentication and pagination, and stores everything in memory so no database is needed.
It's extremely primitive right now and I'm not even sure if this is useful to anyone, but it reduced the time required for my test suite to run by like 90%.
Wouldn't it be easier to define callbacks/behaviours in the code so that people could use Mox to test?
It's a bit of a pain to use a separate server (especially when you consider CI), and the alternative is basically something like Bypass, which is yet another dependency :(