Testing

There are a few techniques for testing your GraphQL::Dataloader setup.

Integration Tests

One important feature of Dataloader is how it manages database access while GraphQL runs queries. You can test that by listening for database queries while running queries, for example, with ActiveRecord:

def test_active_record_queries_are_batched_and_cached
  # set up a listener function
  database_queries = 0
  callback = lambda {|_name, _started, _finished, _unique_id, _payload| database_queries += 1 }

  query_str = <<-GRAPHQL
  {
    a1: author(id: 1) { name }
    a2: author(id: 2) { name }
    b1: book(id: 1) { author { name } }
    b2: book(id: 2) { author { name } }
  }
  GRAPHQL

  # Run the query with the listener
  ActiveSupport::Notifications.subscribed(callback, "sql.active_record") do
    MySchema.execute(query_str)
  end

  # One query for authors, one query for books
  assert_equal 2, database_queries
end

You could also make specific assertions on the queries that are run (see the sql.active_record docs). For other frameworks and databases, check your ORM or library for instrumentation options.

Testing Dataloader Sources

You can also test Dataloader behavior outside of GraphQL using GraphQL::Dataloader.with_dataloading. For example, let’s if you have a Sources::ActiveRecord source defined like so:


module Sources
  class User < GraphQL::Dataloader::Source
    def fetch(ids)
      records = User.where(id: ids)
      # return a list with `nil` for any ID that wasn't found, so the shape matches
      ids.map { |id| records.find { |r| r.id == id.to_i } }
    end
  end
end

You can test it like so:

def test_it_fetches_objects_by_id
  user_1, user_2, user_3 = 3.times.map { User.create! }

  database_queries = 0
  callback = lambda {|_name, _started, _finished, _unique_id, _payload| database_queries += 1 }

  ActiveSupport::Notifications.subscribed(callback, "sql.active_record") do
    GraphQL::Dataloader.with_dataloading do |dataloader|
      req1 = dataloader.with(Sources::ActiveRecord).request(user_1.id)
      req2 = dataloader.with(Sources::ActiveRecord).request(user_2.id)
      req3 = dataloader.with(Sources::ActiveRecord).request(user_3.id)
      req4 = dataloader.with(Sources::ActiveRecord).request(-1)

      # Validate source's matching up of records
      expect(req1.load).to eq(user_1)
      expect(req2.load).to eq(user_2)
      expect(req3.load).to eq(user_3)
      expect(req4.load).to be_nil
    end
  end

  assert_equal 1, database_queries, "All users were looked up at once"
end