question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. ItĀ collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

How to write unit tests for methods that use Knex.

See original GitHub issue

(Originally posted in #1659, moved here for further discussion.)

I’m kind of in the dark on this one - the knex docs cover the barebones of transactions, but when I google ā€œusing knex.js for unit testingā€ and ā€œava.js + knexā€ and ā€œava.js + databaseā€, I couldn’t find anything particularly instructive to show me a good way, so I fell back on my Ruby experience where wrapping a unit test in a transaction is a common technique for reseting the DB after each test.

@odigity I wouldn’t suggest of doing that because your tests will end up using just one connection instead of connection pool and it will not represent real world usage of your app.

That did occur to me, but I was willing to accept that if it allowed me to use a simple, write-once method for implementing post-test DB cleanup. (I did set my pool min/max to 1 to be sure.) If there’s a way to accomplish this while supporting concurrent connections, I will absolute embrace that.

Also its pretty much impossible to implement unless the application you are testing is running its queries in the same transaction that was started inside test code (you would need to start transaction in test then start your app and pass the created transaction to app so that it makes all the queries to the same transaction and nested transactions might behave starngely…).

The way I hoped/expected it to work is:

  1. In each unit test, I create a transaction which produces trx.

  2. I then require the module I want to test and pass the trx object to the module constructor so it will be used by the module, thus resulting in all queries happening inside the transaction.

  3. After the module method returns (or throws error), I run my assertions on the resulting state of the DB, then call trx.rollback() to undo everything from the start to prepare for the next test.

So, that’s what I’m trying to achieve and how I originally intended to achieve it. I’m eager to learn more about:

  1. In what whys I’m misunderstanding how Knex.js works and should be used.

  2. Best practices for writing atomic unit tests for code that touches the database.

Issue Analytics

  • State:closed
  • Created 6 years ago
  • Reactions:8
  • Comments:36 (13 by maintainers)

github_iconTop GitHub Comments

31reactions
odigitycommented, May 21, 2017

Nope - got nothing. Summary in chronological order of sources:

2016-04-21 https://medium.com/@jomaora/knex-bookshelf-mocks-and-unit-tests-cca627565d3

Strategy: Use mock-knex. I don’t want to mock the DB - I want to test my methods against an actual MySQL DB to ensure correct behavior - but I took a look at mock-knex anyway… it may just be the worst designed library I’ve ever encountered. 😦

2016-04-28 http://mherman.org/blog/2016/04/28/test-driven-development-with-node/

Strategy: Rollback/remigrate/reseed DB after each test. That seems like a great deal of overhead for each test, and will run terribly slow. Concurrency could be achieved by generating a UUID for each test’s DB name, but that just seems like an awful solution compared to the elegance of transactions…

2015-09-23 http://stackoverflow.com/a/32749601/210867

Strategy: Use sqlite for testing, create/destroy DB for each test. I’ve covered both reasons I dislike this approach above.

So… still fishing for suggestions, and additional guidance on how Knex transactions actually work, as well as how to properly apply them to my use case.

25reactions
elhigucommented, May 21, 2017

@odigity nicely summed up the bad testing practices šŸ‘

We are doing our ā€œunitā€ tests like this:

  1. Start up system, initialize DB and run migrations

  2. Before each test we truncate all the tables and sequences (with knex-db-manager package)

  3. Insert data required for the test case (we use knex based objection.js ORM for that which allows us to insert nested object hierarchies with single command, it knows how to optimise inserts so that it doesn’t have to do separate insert for each row in the table, but usually just one insert per table)

  4. run 1 test and goto step 2

With e2e tests we have implemented saveState / restoreState (with pg_restore/pg_dump) methods, which allows us to roll back to certain state during the test run, so we don’t have to restart test run every time when some test fails after running 20 minutes of tests.

Read more comments on GitHub >

github_iconTop Results From Across the Web

How can I mock a fake database for when unit testing against ...
Using jest: Create the file /__mocks__/knex.js in your app root: module.exports = () => ({ select: jest.fn().
Read more >
Knex, Bookshelf, mocks and Unit Tests | by Joan Ortega
This is my second story about Knex and Bookshelf. This time I'll talk about mocking these dependencies for unit test.
Read more >
Experimenting with Knex in Node.js Testing Frameworks
One of the trickier parts of unit testing can be mocking out database connections. The ideal unit test involves only testing your own...
Read more >
Testing Knex SQL queries with Jest and testcontainers
In this post, we create test cases that check if the SQL queries executed by these methods work as expected and that they...
Read more >
Test Driven Development with Node, Postgres, and Knex (Red ...
Before we can start testing and writing code we need to set up our project, a database, and all the required dependencies… Project...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found