dittodb

dittodb: A Test Environment for DB Queries in R

https://github.com/ropensci/dittodb

Science Score: 26.0%

This score indicates how likely this project is to be science-related based on various indicators:

  • CITATION.cff file
  • codemeta.json file
    Found codemeta.json file
  • .zenodo.json file
    Found .zenodo.json file
  • DOI references
  • Academic publication links
  • Academic email domains
  • Institutional organization owner
  • JOSS paper metadata
  • Scientific vocabulary similarity
    Low similarity (12.6%) to scientific vocabulary
Last synced: 10 months ago · JSON representation

Repository

dittodb: A Test Environment for DB Queries in R

Basic Info
Statistics
  • Stars: 81
  • Watchers: 4
  • Forks: 15
  • Open Issues: 23
  • Releases: 9
Created over 6 years ago · Last pushed 10 months ago
Metadata Files
Readme Changelog Contributing License Code of conduct Codemeta

README.md

dittodb

CRAN status macOS Linux Windows Codecov test coverage Lifecycle: stable <!-- badges: end -->

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:

r 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

```r startdbcapturing()

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

getanairline(con) DBI::dbDisconnect(con)

stopdbcapturing() ```

RPostgres

```r startdbcapturing()

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

getanairline(con) DBI::dbDisconnect(con)

stopdbcapturing() ```

RSQLite

```r startdbcapturing()

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

getanairline(con) DBI::dbDisconnect(con)

stopdbcapturing() ```

{.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

```r withmockdb({ con <- DBI::dbConnect( RMariaDB::MariaDB(), dbname = "nycflights" )

testthat("We get one airline", { oneairline <- getanairline(con) expects3class(oneairline, "data.frame") expectequal(nrow(oneairline), 1) expectequal(oneairline$carrier, "9E") expectequal(one_airline$name, "Endeavor Air Inc.") }) }) ```

RPostgres

```r withmockdb({ con <- DBI::dbConnect( RPostgres::Postgres(), dbname = "nycflights" )

testthat("We get one airline", { oneairline <- getanairline(con) expects3class(oneairline, "data.frame") expectequal(nrow(oneairline), 1) expectequal(oneairline$carrier, "9E") expectequal(one_airline$name, "Endeavor Air Inc.") }) }) ```

RSQLite

```r withmockdb({ con <- DBI::dbConnect(RSQLite::SQLite(), "nycflights")

testthat("We get one airline", { oneairline <- getanairline(con) expects3class(oneairline, "data.frame") expectequal(nrow(oneairline), 1) expectequal(oneairline$carrier, "9E") expectequal(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.

Owner

  • Name: rOpenSci
  • Login: ropensci
  • Kind: organization
  • Email: info@ropensci.org
  • Location: Berkeley, CA

CodeMeta (codemeta.json)

{
  "@context": "https://doi.org/10.5063/schema/codemeta-2.0",
  "@type": "SoftwareSourceCode",
  "identifier": "dittodb",
  "description": "Testing and documenting code that communicates with remote databases can be painful. Although the interaction with R is usually relatively simple (e.g. data(frames) passed to and from a database), because they rely on a separate service and the data there, testing them can be difficult to set up, unsustainable in a continuous integration environment, or impossible without replicating an entire production cluster. This package addresses that by allowing you to make recordings from your database interactions and then play them back while testing (or in other contexts) all without needing to spin up or have access to the database your code would typically connect to.",
  "name": "dittodb: A Test Environment for Database Requests",
  "relatedLink": [
    "https://dittodb.jonkeane.com/",
    "https://CRAN.R-project.org/package=dittodb"
  ],
  "codeRepository": "https://github.com/ropensci/dittodb",
  "issueTracker": "https://github.com/ropensci/dittodb/issues",
  "license": "https://spdx.org/licenses/Apache-2.0",
  "version": "0.1.9.9000",
  "programmingLanguage": {
    "@type": "ComputerLanguage",
    "name": "R",
    "url": "https://r-project.org"
  },
  "runtimePlatform": "R version 4.5.1 (2025-06-13)",
  "provider": {
    "@id": "https://cran.r-project.org",
    "@type": "Organization",
    "name": "Comprehensive R Archive Network (CRAN)",
    "url": "https://cran.r-project.org"
  },
  "author": [
    {
      "@type": "Person",
      "givenName": "Jonathan",
      "familyName": "Keane",
      "email": "jkeane@gmail.com",
      "@id": "https://orcid.org/0000-0001-7087-9776"
    },
    {
      "@type": "Person",
      "givenName": "Mauricio",
      "familyName": "Vargas",
      "email": "mvargas@dcc.uchile.cl",
      "@id": "https://orcid.org/0000-0003-1017-7574"
    }
  ],
  "maintainer": [
    {
      "@type": "Person",
      "givenName": "Jonathan",
      "familyName": "Keane",
      "email": "jkeane@gmail.com",
      "@id": "https://orcid.org/0000-0001-7087-9776"
    }
  ],
  "softwareSuggestions": [
    {
      "@type": "SoftwareApplication",
      "identifier": "bit64",
      "name": "bit64",
      "provider": {
        "@id": "https://cran.r-project.org",
        "@type": "Organization",
        "name": "Comprehensive R Archive Network (CRAN)",
        "url": "https://cran.r-project.org"
      },
      "sameAs": "https://CRAN.R-project.org/package=bit64"
    },
    {
      "@type": "SoftwareApplication",
      "identifier": "callr",
      "name": "callr",
      "provider": {
        "@id": "https://cran.r-project.org",
        "@type": "Organization",
        "name": "Comprehensive R Archive Network (CRAN)",
        "url": "https://cran.r-project.org"
      },
      "sameAs": "https://CRAN.R-project.org/package=callr"
    },
    {
      "@type": "SoftwareApplication",
      "identifier": "covr",
      "name": "covr",
      "provider": {
        "@id": "https://cran.r-project.org",
        "@type": "Organization",
        "name": "Comprehensive R Archive Network (CRAN)",
        "url": "https://cran.r-project.org"
      },
      "sameAs": "https://CRAN.R-project.org/package=covr"
    },
    {
      "@type": "SoftwareApplication",
      "identifier": "dplyr",
      "name": "dplyr",
      "provider": {
        "@id": "https://cran.r-project.org",
        "@type": "Organization",
        "name": "Comprehensive R Archive Network (CRAN)",
        "url": "https://cran.r-project.org"
      },
      "sameAs": "https://CRAN.R-project.org/package=dplyr"
    },
    {
      "@type": "SoftwareApplication",
      "identifier": "dbplyr",
      "name": "dbplyr",
      "provider": {
        "@id": "https://cran.r-project.org",
        "@type": "Organization",
        "name": "Comprehensive R Archive Network (CRAN)",
        "url": "https://cran.r-project.org"
      },
      "sameAs": "https://CRAN.R-project.org/package=dbplyr"
    },
    {
      "@type": "SoftwareApplication",
      "identifier": "knitr",
      "name": "knitr",
      "provider": {
        "@id": "https://cran.r-project.org",
        "@type": "Organization",
        "name": "Comprehensive R Archive Network (CRAN)",
        "url": "https://cran.r-project.org"
      },
      "sameAs": "https://CRAN.R-project.org/package=knitr"
    },
    {
      "@type": "SoftwareApplication",
      "identifier": "nycflights13",
      "name": "nycflights13",
      "provider": {
        "@id": "https://cran.r-project.org",
        "@type": "Organization",
        "name": "Comprehensive R Archive Network (CRAN)",
        "url": "https://cran.r-project.org"
      },
      "sameAs": "https://CRAN.R-project.org/package=nycflights13"
    },
    {
      "@type": "SoftwareApplication",
      "identifier": "odbc",
      "name": "odbc",
      "provider": {
        "@id": "https://cran.r-project.org",
        "@type": "Organization",
        "name": "Comprehensive R Archive Network (CRAN)",
        "url": "https://cran.r-project.org"
      },
      "sameAs": "https://CRAN.R-project.org/package=odbc"
    },
    {
      "@type": "SoftwareApplication",
      "identifier": "RMariaDB",
      "name": "RMariaDB",
      "provider": {
        "@id": "https://cran.r-project.org",
        "@type": "Organization",
        "name": "Comprehensive R Archive Network (CRAN)",
        "url": "https://cran.r-project.org"
      },
      "sameAs": "https://CRAN.R-project.org/package=RMariaDB"
    },
    {
      "@type": "SoftwareApplication",
      "identifier": "RPostgres",
      "name": "RPostgres",
      "provider": {
        "@id": "https://cran.r-project.org",
        "@type": "Organization",
        "name": "Comprehensive R Archive Network (CRAN)",
        "url": "https://cran.r-project.org"
      },
      "sameAs": "https://CRAN.R-project.org/package=RPostgres"
    },
    {
      "@type": "SoftwareApplication",
      "identifier": "RPostgreSQL",
      "name": "RPostgreSQL",
      "provider": {
        "@id": "https://cran.r-project.org",
        "@type": "Organization",
        "name": "Comprehensive R Archive Network (CRAN)",
        "url": "https://cran.r-project.org"
      },
      "sameAs": "https://CRAN.R-project.org/package=RPostgreSQL"
    },
    {
      "@type": "SoftwareApplication",
      "identifier": "RSQLite",
      "name": "RSQLite",
      "provider": {
        "@id": "https://cran.r-project.org",
        "@type": "Organization",
        "name": "Comprehensive R Archive Network (CRAN)",
        "url": "https://cran.r-project.org"
      },
      "sameAs": "https://CRAN.R-project.org/package=RSQLite"
    },
    {
      "@type": "SoftwareApplication",
      "identifier": "spelling",
      "name": "spelling",
      "provider": {
        "@id": "https://cran.r-project.org",
        "@type": "Organization",
        "name": "Comprehensive R Archive Network (CRAN)",
        "url": "https://cran.r-project.org"
      },
      "sameAs": "https://CRAN.R-project.org/package=spelling"
    },
    {
      "@type": "SoftwareApplication",
      "identifier": "testthat",
      "name": "testthat",
      "provider": {
        "@id": "https://cran.r-project.org",
        "@type": "Organization",
        "name": "Comprehensive R Archive Network (CRAN)",
        "url": "https://cran.r-project.org"
      },
      "sameAs": "https://CRAN.R-project.org/package=testthat"
    },
    {
      "@type": "SoftwareApplication",
      "identifier": "withr",
      "name": "withr",
      "provider": {
        "@id": "https://cran.r-project.org",
        "@type": "Organization",
        "name": "Comprehensive R Archive Network (CRAN)",
        "url": "https://cran.r-project.org"
      },
      "sameAs": "https://CRAN.R-project.org/package=withr"
    },
    {
      "@type": "SoftwareApplication",
      "identifier": "rmarkdown",
      "name": "rmarkdown",
      "provider": {
        "@id": "https://cran.r-project.org",
        "@type": "Organization",
        "name": "Comprehensive R Archive Network (CRAN)",
        "url": "https://cran.r-project.org"
      },
      "sameAs": "https://CRAN.R-project.org/package=rmarkdown"
    }
  ],
  "softwareRequirements": {
    "1": {
      "@type": "SoftwareApplication",
      "identifier": "R",
      "name": "R",
      "version": ">= 3.3.0"
    },
    "2": {
      "@type": "SoftwareApplication",
      "identifier": "DBI",
      "name": "DBI",
      "provider": {
        "@id": "https://cran.r-project.org",
        "@type": "Organization",
        "name": "Comprehensive R Archive Network (CRAN)",
        "url": "https://cran.r-project.org"
      },
      "sameAs": "https://CRAN.R-project.org/package=DBI"
    },
    "3": {
      "@type": "SoftwareApplication",
      "identifier": "digest",
      "name": "digest",
      "provider": {
        "@id": "https://cran.r-project.org",
        "@type": "Organization",
        "name": "Comprehensive R Archive Network (CRAN)",
        "url": "https://cran.r-project.org"
      },
      "sameAs": "https://CRAN.R-project.org/package=digest"
    },
    "4": {
      "@type": "SoftwareApplication",
      "identifier": "glue",
      "name": "glue",
      "provider": {
        "@id": "https://cran.r-project.org",
        "@type": "Organization",
        "name": "Comprehensive R Archive Network (CRAN)",
        "url": "https://cran.r-project.org"
      },
      "sameAs": "https://CRAN.R-project.org/package=glue"
    },
    "5": {
      "@type": "SoftwareApplication",
      "identifier": "methods",
      "name": "methods"
    },
    "6": {
      "@type": "SoftwareApplication",
      "identifier": "rlang",
      "name": "rlang",
      "provider": {
        "@id": "https://cran.r-project.org",
        "@type": "Organization",
        "name": "Comprehensive R Archive Network (CRAN)",
        "url": "https://cran.r-project.org"
      },
      "sameAs": "https://CRAN.R-project.org/package=rlang"
    },
    "7": {
      "@type": "SoftwareApplication",
      "identifier": "utils",
      "name": "utils"
    },
    "8": {
      "@type": "SoftwareApplication",
      "identifier": "lifecycle",
      "name": "lifecycle",
      "provider": {
        "@id": "https://cran.r-project.org",
        "@type": "Organization",
        "name": "Comprehensive R Archive Network (CRAN)",
        "url": "https://cran.r-project.org"
      },
      "sameAs": "https://CRAN.R-project.org/package=lifecycle"
    },
    "SystemRequirements": null
  },
  "fileSize": "641.832KB",
  "releaseNotes": "https://github.com/ropensci/dittodb/blob/main/NEWS.md",
  "readme": "https://github.com/ropensci/dittodb/blob/main/README.md",
  "contIntegration": [
    "https://github.com/ropensci/dittodb/actions?workflow=check-macOS",
    "https://github.com/ropensci/dittodb/actions?workflow=check-linux",
    "https://github.com/ropensci/dittodb/actions?workflow=check-windows",
    "https://app.codecov.io/gh/ropensci/dittodb?branch=main"
  ],
  "developmentStatus": "https://lifecycle.r-lib.org/articles/stages.html"
}

GitHub Events

Total
  • Issues event: 3
  • Watch event: 2
  • Delete event: 1
  • Push event: 14
  • Pull request event: 1
  • Create event: 2
Last Year
  • Issues event: 3
  • Watch event: 2
  • Delete event: 1
  • Push event: 14
  • Pull request event: 1
  • Create event: 2

Issues and Pull Requests

Last synced: 10 months ago

All Time
  • Total issues: 50
  • Total pull requests: 65
  • Average time to close issues: 6 months
  • Average time to close pull requests: 2 days
  • Total issue authors: 14
  • Total pull request authors: 10
  • Average comments per issue: 1.68
  • Average comments per pull request: 0.88
  • Merged pull requests: 61
  • Bot issues: 0
  • Bot pull requests: 0
Past Year
  • Issues: 0
  • Pull requests: 0
  • Average time to close issues: N/A
  • Average time to close pull requests: N/A
  • Issue authors: 0
  • Pull request authors: 0
  • Average comments per issue: 0
  • Average comments per pull request: 0
  • Merged pull requests: 0
  • Bot issues: 0
  • Bot pull requests: 0
Top Authors
Issue Authors
  • jonkeane (31)
  • psimm (3)
  • ndiquattro (3)
  • pachadotdev (2)
  • majazaloznik (2)
  • Ale0x78 (1)
  • etiennebr (1)
  • Kjir (1)
  • sebastian-fox (1)
  • krlmlr (1)
  • kenshuri (1)
  • cocinerox (1)
  • KoderKow (1)
  • seasick (1)
Pull Request Authors
  • jonkeane (51)
  • pachadotdev (6)
  • maelle (3)
  • KoderKow (3)
  • majazaloznik (2)
  • etiennebr (1)
  • hadley (1)
  • sandstumpen (1)
  • krlmlr (1)
  • cocinerox (1)
Top Labels
Issue Labels
ropensci reviewer comments (5) good first issue (1)
Pull Request Labels

Packages

  • Total packages: 1
  • Total downloads:
    • cran 476 last-month
  • Total docker downloads: 41,971
  • Total dependent packages: 1
  • Total dependent repositories: 3
  • Total versions: 10
  • Total maintainers: 1
cran.r-project.org: dittodb

A Test Environment for Database Requests

  • Versions: 10
  • Dependent Packages: 1
  • Dependent Repositories: 3
  • Downloads: 476 Last month
  • Docker Downloads: 41,971
Rankings
Docker downloads count: 0.6%
Stargazers count: 4.7%
Forks count: 5.1%
Average: 11.1%
Dependent repos count: 16.5%
Dependent packages count: 18.2%
Downloads: 21.6%
Maintainers (1)
Last synced: 10 months ago

Dependencies

DESCRIPTION cran
  • DBI * depends
  • R >= 3.3.0 depends
  • digest * imports
  • glue * imports
  • lifecycle * imports
  • methods * imports
  • utils * imports
  • RMariaDB * suggests
  • RPostgreSQL * suggests
  • RPostgres * suggests
  • RSQLite * suggests
  • callr * suggests
  • covr * suggests
  • dbplyr * suggests
  • dplyr * suggests
  • knitr * suggests
  • lintr * suggests
  • nycflights13 * suggests
  • odbc * suggests
  • rmarkdown * suggests
  • spelling * suggests
  • testthat * suggests
  • withr * suggests
.github/workflows/check-linux-testthat-2e-3e.yaml actions
  • actions/cache v2 composite
  • actions/checkout v3 composite
  • actions/upload-artifact main composite
  • r-lib/actions/setup-pandoc v2 composite
  • r-lib/actions/setup-r v2 composite
  • r-lib/actions/setup-r-dependencies v2 composite
.github/workflows/check-linux.yaml actions
  • actions/checkout v3 composite
  • actions/upload-artifact main composite
  • r-lib/actions/setup-pandoc v2 composite
  • r-lib/actions/setup-r v2 composite
  • r-lib/actions/setup-r-dependencies v2 composite
  • r-lib/actions/setup-tinytex v2 composite
.github/workflows/check-macOS.yaml actions
  • actions/checkout v3 composite
  • actions/upload-artifact main composite
  • r-lib/actions/setup-pandoc v2 composite
  • r-lib/actions/setup-r v2 composite
  • r-lib/actions/setup-r-dependencies v2 composite
  • r-lib/actions/setup-tinytex v2 composite
.github/workflows/check-windows.yaml actions
  • actions/cache v2 composite
  • actions/checkout v3 composite
  • actions/upload-artifact main composite
  • r-lib/actions/setup-pandoc v2 composite
  • r-lib/actions/setup-r v2 composite
  • r-lib/actions/setup-r-dependencies v2 composite
  • r-lib/actions/setup-tinytex v2 composite
.github/workflows/pkgdown-codemeta.yaml actions
  • actions/checkout v3 composite
  • r-lib/actions/setup-pandoc v2 composite
  • r-lib/actions/setup-r v2 composite