Giter VIP home page Giter VIP logo

dittodb's Introduction

dittodb

CRAN status macOS Linux Windows Codecov test coverage Lifecycle: stable

dittodb is a package that makes testing against databases easy. When writing code that relies on interactions with databases, testing has been difficult without recreating test databases in your continuous integration (aka CI) environment, or resorting to using SQLite databases instead of the database engines you have in production. Both have their downsides: recreating database infrastructure is slow, error prone, and hard to iterate with. Using SQLite works well, right up until you use a feature (like a full outer join) or has quirks that might differ from your production database. dittodb solves this by recording database interactions, saving them as mocks, and then replaying them seamlessly during testing. This means that if you can get a query from your database, you can record the response and reliably reproduce that response in tests.

dittodb is heavily inspired by {httptest}, if you've used {httptest} before, you'll find many of the interactions similar.

A quick example

Say we have a database with some {nycflights} data in it and we are writing functions that query this data that we want to test.

For example, we have the simple function that retrieves one airline:

get_an_airline <- function(con) {
  return(dbGetQuery(con, "SELECT carrier, name FROM airlines LIMIT 1"))
}

But we want to make sure that this function returns what we expect. To do this, we first record the response we get from the production database:

{.tabset}

RMariaDB

start_db_capturing()

con <- DBI::dbConnect(
  RMariaDB::MariaDB(),
  dbname = "nycflights"
)

get_an_airline(con)
DBI::dbDisconnect(con)

stop_db_capturing()

RPostgres

start_db_capturing()

con <- DBI::dbConnect(
  RPostgres::Postgres(),
  dbname = "nycflights"
)

get_an_airline(con)
DBI::dbDisconnect(con)

stop_db_capturing()

RSQLite

start_db_capturing()

con <- DBI::dbConnect(RSQLite::SQLite(), "nycflights")

get_an_airline(con)
DBI::dbDisconnect(con)

stop_db_capturing()

{.tabset}

This will run the query from get_an_airline(), and save the response in a mock directory and file. Then, when we are testing, we can use the following:

RMariaDB

with_mock_db({
  con <- DBI::dbConnect(
    RMariaDB::MariaDB(),
    dbname = "nycflights"
  )
  
  test_that("We get one airline", {
    one_airline <- get_an_airline(con)
    expect_s3_class(one_airline, "data.frame")
    expect_equal(nrow(one_airline), 1)
    expect_equal(one_airline$carrier, "9E")
    expect_equal(one_airline$name, "Endeavor Air Inc.")
  })
})

RPostgres

with_mock_db({
  con <- DBI::dbConnect(
    RPostgres::Postgres(),
    dbname = "nycflights"
  )
  
  test_that("We get one airline", {
    one_airline <- get_an_airline(con)
    expect_s3_class(one_airline, "data.frame")
    expect_equal(nrow(one_airline), 1)
    expect_equal(one_airline$carrier, "9E")
    expect_equal(one_airline$name, "Endeavor Air Inc.")
  })
})

RSQLite

with_mock_db({
  con <- DBI::dbConnect(RSQLite::SQLite(), "nycflights")
  
  test_that("We get one airline", {
    one_airline <- get_an_airline(con)
    expect_s3_class(one_airline, "data.frame")
    expect_equal(nrow(one_airline), 1)
    expect_equal(one_airline$carrier, "9E")
    expect_equal(one_airline$name, "Endeavor Air Inc.")
  })
})

All without having to ever set a database up on Travis or GitHub Actions ๐ŸŽ‰

Installation

Currently, dittodb is on CRAN (The Comprehensive R Archive Network), so you can install it with install.packages("dittodb").

Installing a development version

If you would like to use the development version, you can install from GitHub with: remotes::install_github("ropensci/dittodb")

Note You may need to add @main at the end if you are using a version of {remotes} prior to 2.2.0. Alternatively, you can use remotes::install_git() directly: remotes::install_git("https://github.com/ropensci/dittodb.git")

Setup a package to use dittodb

Use the function dittodb::use_dittodb() to easily get started using dittodb. It will add dittodb to Suggests in the DESCRIPTION file and add library(dittodb) to tests/testthat/helper.R.

Development

There is extensive information about developing dittodb in the vignette Developing dittodb, please read that before trying to make changes to dittodb or running any of the scripts provided in the db-setup directory.

In order to test dittodb recording functionality locally or on continuous integration, it is helpful to have databases with test data available. This can be accomplished using the scripts in the db-setup directory. By default, dittodb does not run any tests that require database infrastructure locally.

To get local databases, the easiest way is to use docker and run either the db-setup/local-mariadb-docker-setup.sh or db-setup/local-postgres-docker-setup.sh which will pull a docker image and set up a test database with the user and passwords that the dittodb tests are expecting (and will stop and remove the docker images if they are present).

On continuous integration, (using GitHub Actions) these scripts in the db-setup directory are used to set up these test databases so we can run integration tests (predominantly in the file tests/testthat/test-dbi-generic-integration.R).

Code of Conduct

Please note that the dittodb project is released with a Contributor Code of Conduct. By contributing to this project, you agree to abide by its terms.

dittodb's People

Contributors

jonkeane avatar actions-user avatar koderkow avatar maelle avatar sandstumpen avatar etiennebr avatar hadley avatar krlmlr avatar cocinerox avatar majazaloznik 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.