Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Testing other code execution inside a command #247

Closed
CeeBeeUK opened this issue Mar 30, 2020 · 8 comments
Closed

Testing other code execution inside a command #247

CeeBeeUK opened this issue Mar 30, 2020 · 8 comments
Labels

Comments

@CeeBeeUK
Copy link

CeeBeeUK commented Mar 30, 2020

So I have a simple command that shows the user a typing message while queuing a sidekiq job that processes a long running task and outputs further details...

module MyBot
  module Commands
    class IntegrationTests < SlackRubyBot::Commands::Base
      command 'run tests' do |client, data, _match|
        client.typing(channel: data.channel)
        StartIntegrationTestsWorker.perform_async(data)
      end
    end
  end
end

My simple test ensures that start_typing is received..

require 'spec_helper'

describe MyBot::Commands::IntegrationTests, :vcr do
  let(:user_input) { "#{SlackRubyBot.config.user} run tests" }

  context 'when user requests a test run' do
    it 'starts typing' do
      expect_any_instance_of(StartIntegrationTestsWorker).to receive(:perform_async)
      expect(message: user_input, channel: 'channel').to start_typing(channel: 'channel')
    end
  end
end

Is there a way to successfully test the execution of code other than the chat message?
This all works in reality, but despite trying the above and...
expect(StartIntegrationTestsWorker).to receive(:perform_async)

let(:double) { class_double(StartIntegrationTestsWorker) }
expect(double).to receive(:perform_async)

and other varieties I cannot successfully get the tests to simulate calling the StartIntegrationTestsWorker.
Do the start_typing, respond_with_slack_message and other rspec matchers mock out the entire process? If so, is there a guide anywhere for testing other code handling inside commands?

@dblock
Copy link
Collaborator

dblock commented Mar 30, 2020

I think the issue is simpler here. You are calling StartIntegrationTestsWorker.perform_async, which is a class method on StartIntegrationTestsWorker, not an instance method. The above expect_any_instance_of is expecting an instance, StartIntegrationTestsWorker.new, and so doesn't work.

The expect(StartIntegrationTestsWorker).to receive(:perform_async) version should work. Are you sure it does not?

@dblock
Copy link
Collaborator

dblock commented Mar 30, 2020

The start_typing, and respond_with_slack_message and other rspec matchers setup a message handler/hook instance that in a real app is setup listening on slack's message events, and keep track of the client instance, so you don't have to.

@dblock
Copy link
Collaborator

dblock commented Mar 30, 2020

Minor, but I don't remember if we handle commands with spaces, run tests. If it doesn't work try without?

@CeeBeeUK
Copy link
Author

I started with expect(StartIntegrationTestsWorker).to receive(:perform_async)
and have also tried expect(StartIntegrationTestsWorker).to receive(:perform) in case ruby magic was translating it internally!
Both fail with

(StartIntegrationTestsWorker (class)).perform(*(any args))
           expected: 1 time with any arguments
           received: 0 times with any arguments

This is actually working nicely in Slack!
gif-complete
If I take out the StartIntegrationTestsWorker line the start_typing(channel: 'channel') test passes fine 🤔
Thanks for the response and clarification, knowing that it should work, I'll keep playing!

Thanks for maintaining all these repos!

@CeeBeeUK
Copy link
Author

CeeBeeUK commented Mar 30, 2020

Hmm, looking at my other tests, I am using a different format

expect { perform }.to change(MonitorTestRunWorker.jobs, :size).by(1)

In the same tests

      it 'works?' do
        expect(MonitorTestRunWorker).to receive(:perform)
        perform
      end

fails.

Can I call message_send in a block?
failing, but something like

    it 'triggers the sidekiq job' do
      expect { SlackRubyBot::Hooks::Message.new(message: user_input, channel: 'channel') }
        .to change(MonitorTestRunWorker.jobs, :size).by(1)
    end

@dblock
Copy link
Collaborator

dblock commented Mar 30, 2020

If I take out the StartIntegrationTestsWorker line the start_typing(channel: 'channel') test passes fine 🤔

Is this code valid at all? Add a puts above to see if it's called? Then wrap it in an exception handler, maybe there's a typo? :)

command 'run tests' do |client, data, _match|
  begin
        client.typing(channel: data.channel)
        StartIntegrationTestsWorker.perform_async(data)
  rescue Exception => e
      puts e
      raise
  end
end

See anything?

@dblock
Copy link
Collaborator

dblock commented Mar 30, 2020

Can I call message_send in a block?
failing, but something like

    it 'triggers the sidekiq job' do
      expect { SlackRubyBot::Hooks::Message.new(message: user_input, channel: 'channel') }
        .to change(MonitorTestRunWorker.jobs, :size).by(1)
    end

yes you can

@dblock
Copy link
Collaborator

dblock commented Mar 30, 2020

If you're still having trouble, feel free to upload the project somewhere and I can try to help.

Either way this is 100% not a problem with the bot library, I'm going to close this for housekeeping, but feel free to add more questions and I'll do my best to answer.

@dblock dblock closed this as completed Mar 30, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants