r-lib / testthat

An R 📦 to make testing 😀
https://testthat.r-lib.org
Other
872 stars 314 forks source link

Additional matchers #42

Closed ssimeonov closed 11 years ago

ssimeonov commented 11 years ago

I've found the following matchers useful to highlight the intent of my expectations. If you think any of them could be useful more broadly, let me know and I'll submit a pull request.

context("MongoCollection")

test_that("local connection to test DB", { 
  subject <- MongoCollection$new(test_db(), 'test')

  expect_proto(subject, 'MongoCollection')
  expect_interface(subject, 'add', 'count', 'db', 'drop', 'find', 'find_one', 'full_name', 'insert', 'is_connected', 'name', 'remove')

  expect_true(s$is_connected())
  expect_equal(s$name(), 'test')
  expect_equal(s$full_name(), paste(DB, 'test', sep='.'))
})

test_that("CRUD", { 
  data <- list(name='sim', tags=c('founder', 'cto', 'angel'))
  coll <- MongoCollection$new(test_db(), 'test')
  coll$insert(data)

  subject <- coll$find(query = list(name = 'sim'))
  expect_length(subject, 1)

  subject <- subject[[1]]
  expect_mongo_doc(subject)
  expect_includes(subject, data)
})
hadley commented 11 years ago

Are those for reference classes? They look interesting.

ssimeonov commented 11 years ago

No, I have gotten into the habit of using proto instead of R's native classes. I find the latter a bit painful.

Here is my test_that "utilities" file: https://gist.github.com/3446827 One thing I've learned about TDD is to invest early in higher-level abstractions that make test writing faster. This usually also helps make the intent of the expectations clearer. An expectation such as expect_interface is very readable and captures in a single line what would usually take many separate expectations while producing failure messages that are at least as meaningful as the ones a developer would get from something like expect_true(is.function(subject$do.something)).

It would be really cool if there was a way to build up a suite of higher-level expectations for test_that. If you like that idea, perhaps you can create a directory structure where these can be added as separate files and then the community can send pull requests you can curate + decide what should go into the test_that core. If this were to happen, I'd break my utilities file into at least three separate ones:

  1. Generic matchers
    • expect_null
    • expect_list
    • expect_function
    • expect_interface
    • expect_length
    • expect_includes
  2. Proto matchers
    • expect_proto
    • proto overloads for expect_interface
  3. MongoDB matchers
    • expect_mongo_doc
hadley commented 11 years ago

Those look cool. I'm not sure whether I want to keep testthat "lean and mean", with the just the minimal set of expectations (and thus encouraging people to write their own) or include everything but the kitchen sink. It's useful to talk about either way.

hadley commented 11 years ago

I think these are a little too specific for testthat, but I'm happy for you to persuade me otherwise.

ssimeonov commented 11 years ago

Hadley, just so I understand how you think about this, what is the alternative to a specific matcher? How would you express this intent using the existing matchers?

hadley commented 11 years ago

In my mind, the proto and mongodb expectations are clearly outside the scope of testthat. They belong in either in the proto/mongodb packages, or in something like testthatProto.

Some of the others already have existing alternatives:

expect_includes might be sufficiently general and useful to be included in testthat, but it's not completely obvious how it works. Could you file a separate issue for that, including a couple of examples?