Skip to content

Client: Testing

Shaun McCormick edited this page Dec 3, 2022 · 2 revisions

With regards to server testing in gruf, there is gruf-rspec, which assists with mocking and validating server responses. As for handling clients, the best way to handle this is dependency injection.

Here's some examples of one way to handle it in an RSpec testing suite. Let's say you have a Services::Accounts::Service gRPC service. You can extend Gruf::Client like so:

module Accounts
  class Client < ::Gruf::Client
    def initialize(hostname:, options: {})
      opts = {
        service: ::Services::Accounts,
        options: {
          hostname: hostname # and other things if needed
        }
      }.merge(options)
      super(opts)
    end
  end
end

From there, you inject it into your service class:

module Accounts
  class Service
    def initialize(client: nil)
      @client = client || ::Accounts::Client.new(hostname: 'my.hostname:1234')
    end
    
    def create(name:)
      response = @client.call(:CreateAccount, name: name.to_s)
      AccountEntity.new(name: response.message.name)
    rescue Gruf::Client::Error => e
      raise Accounts::Errors::FailedCreation, e.message
    end
  end
end

Or something similar. From there, you can just inject a dummy client in tests:

describe Accounts::Service do
  let(:service) { described_class.new(client: client) }
  let(:client) { double(:client, call: call_result) }

  describe '#create' do
    let(:name) { "Bob's Burgers" }
    let(:call_result) { CreateAccountResp.new(name: name) }

    subject { service.create(name: name) }

    it 'creates the account' do
      expect(subject).to be_a(AccountEntity)
      expect(subject.name).to eq name
    end
  end
end

It is highly recommended to use something like dry-system for dependency injection, but wiring the dependencies up manually in the initializer is also acceptable.