Giter Club home page Giter Club logo

testing-code-that-accesses-db-in-haskell's Introduction

5 Ways to Test Application Code that Accesses a Database in Haskell

This repository contains 5 separate Haskell projects. Each project demonstrates a different way of testing application code that accesses a database.

These five Haskell projects were created for the blog post here, which explains the pros and cons of each approach. Please see the blog post for more information. Please see below for more information about the application in question.

The five projects are separated into two groups. Two of the projects are in the with-db/ directory, and the other three projects are in the without-db/ directory.

The two projects in the with-db/ directory access a database in the tests. The three projects in the without-db/ directory do not access a database in the tests.

with-db/ directory

There are two projects in the with-db/ directory. These two projects connect to an actual database even in the tests.

  • with-db/test-database/
    • This approach uses two separate databases. There is a production database and a test database. When unit tests are run, they are only accessing the test database. When code is run in production, it is only accessing the production database.
  • with-db/in-memory-database/
    • This approach is similar to the previous one, except an in-memory database is used for the test database.

without-db/ directory

There are three projects in the without-db/ directory. These three projects do not connect to an actual database in the tests. This has the benefit of making the tests not dependent on a database.

The three projects are as follows:

  • without-db/typeclass/
    • This approach abstracts out database access using a typeclass. In production, there is an instance of the typeclass that accesses the database. For testing, there is an instance of the typeclass that simulates a database with a hashmap.
  • without-db/datatype/
    • This is similar to the typeclass approach, but instead of using a typeclass, it just has a datatype that represents methods to access a database. In production the datatype is filled in with methods that access a database, while in tests the datatype is filled in with methods that simulate accessing a database by using a hashmap.
  • without-db/free-monad/
    • This approach uses a free-monad to make a DSL to describe database access. Two separate interpreters for the DSL are created. One interpreter is used in production and one interpreter is used for tests. The interpreter used in production actually interacts with the database (e.g. putting data into the database and getting data out of the database). The interpreter used for tests simulates a database using a hashmap.

Explanation of the Application

All 5 projects implement a similar application. The application is a simple REST API. It uses servant to define the API.

The API allows the user to operate on blog posts. The API has 4 endpoints that correspond to CRUD operations on blog posts.

API

  • Create
    • This lets you create a new blog post on the server.
    • METHOD: POST
    • URL: http://localhost:8080/create
    • BODY: blog post JSON
      • EXAMPLE: {"title": "example title", "content": "example content"}
    • RETURNS: id of new blog post
  • Read
  • Update
    • This lets you update an existing blog post.
    • METHOD: PUT
    • URL: http://localhost:8080/update/
    • BODY: blog post JSON
      • EXAMPLE: {"title": "updated title", "content": "updated content"}
    • RETURNS: nothing
  • Delete

Run the API

The following shows how to build and run the API on the command line. It is similar for all projects. The without-db/free-monad/ project is used below as an example.

The following uses the stack build tool. You must have stack installed.

Build the API

$ cd without-db/free-monad/
$ stack build

Run Unit Tests

$ stack test

Run the API

$ stack exec free-monad-exe

api running on port 8080...

Test the API from the Command Line

You can test a REST API easily with cURL. First, run stack exec free-monad-exe in one terminal, then in another terminal use cURL like below:

# create a new blog post
$ curl -D - -H "Content-Type: application/json" -X POST -d '{"title": "example title", "content": "example content"}' http://localhost:8080/create

HTTP/1.1 201 Created
Transfer-Encoding: chunked
Date: Sat, 17 Oct 2015 23:37:32 GMT
Server: Warp/3.1.3.1
Content-Type: application/json

1

# read the blog post we just created
$ curl -D - -H "Content-Type: application/json" -X GET http://localhost:8080/read/1
HTTP/1.1 200 OK

Transfer-Encoding: chunked
Date: Sat, 17 Oct 2015 23:38:53 GMT
Server: Warp/3.1.3.1
Content-Type: application/json

{"content":"example content","title":"example title"}

# update the blog post to change the content
$ curl -D - -H "Content-Type: application/json" -X PUT -d '{"title": "example title", "content": "new content"}' http://localhost:8080/update/1

HTTP/1.1 204 No Content
Date: Sat, 17 Oct 2015 23:40:24 GMT
Server: Warp/3.1.3.1

# read the updated blog post
$ curl -D - -H "Content-Type: application/json" -X GET http://localhost:8080/read/1
HTTP/1.1 200 OK

Transfer-Encoding: chunked
Date: Sat, 17 Oct 2015 23:38:53 GMT
Server: Warp/3.1.3.1
Content-Type: application/json

{"content":"new content","title":"example title"}

# delete the blog post
$ curl -D - -H "Content-Type: application/json" -X DELETE http://localhost:8080/delete/1

HTTP/1.1 204 No Content
Date: Sat, 17 Oct 2015 23:42:07 GMT
Server: Warp/3.1.3.1

$

testing-code-that-accesses-db-in-haskell's People

Contributors

cdepillabout avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.