# Advice on writing Ruby tests for plugins

**URL:** https://meta.discourse.org/t/advice-on-writing-ruby-tests-for-plugins/108110
**Category:** Development
**Created:** [February 1, 2019, 9:52am UTC](https://meta.discourse.org/t/advice-on-writing-ruby-tests-for-plugins/108110 "2019-02-01T09:52:27Z")
**Posts on this page:** 15
**Page:** 1

<div class="post-metadata">

### Author: ![kleinfreund](https://avatars.discourse-cdn.com/v4/letter/k/a6a055/32.png) [@kleinfreund](https://meta.discourse.org/u/kleinfreund)
#### Post date: [February 1, 2019, 9:52am UTC](https://meta.discourse.org/t/advice-on-writing-ruby-tests-for-plugins/108110/1 "2019-02-01T09:52:27Z")

</div>

One can write tests for the backend of a plugin. For example, I created the following file in my plugin directory:

`spec/lib/route_store_spec.rb`:

```ruby
require 'rails_helper'

describe MyPlugin::RouteStore do
  describe ".get_routes" do
    it "should return a Hash" do
      expect(described_class.get_routes().is_a?(Hash)).to be true
    end
  end
end

```

And then, I run the tests like this from Discourse’s root directory:

```sh
bundle exec rake plugin:spec["my-plugin-dir"]

```

**/!\ Update** : Should you get the error **`zsh: no matches found: plugin:spec[my-plugin-dir]`**, that’s a [known issue with zsh](https://github.com/robbyrussell/oh-my-zsh/issues/31). You can workaround it by running the tests like this instead:

```sh
bundle exec rake "plugin:spec[my-plugin-dir]"

```

> **Old content before adding the update note**
>
> First of all, the following for running the tests don’t work although I see it recommended as the way to run the tests in the forum a lot:
> 
> - `bundle exec rake plugin:spec["disraptor"]`: Errors with
> 
> - `bundle exec rake plugin:spec disraptor`: errors on a different plugin’s tests with:

* * *

Now, I have a general question regarding testability of certain code. The method I want to test in the code above looks like this:

`described_class.get_routes()`:

```ruby
def get_routes
  return PluginStore.get(MyPlugin::PLUGIN_NAME, 'key') || {}
end

```

Both parameters of `PluginStore.get` are hard-coded and currently cannot be changed from within the tests. This makes the method untestable because I would need to test actual plugin data from the store which I cannot rely on being there.

Discourse’s own tests for the `discourse-narrative-bot` plugin work around this by making the key parameter a parameter in the method they want to test (see `plugins/discourse-narrative-bot/spec/discourse_narrative_bot/store_spec.rb` for reference).

Are there other options for testing a plugin’s store?

---

<div class="post-metadata">

### Author: ![david](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/david/32/157490_2.png) [@david](https://meta.discourse.org/u/david)
#### Post date: [February 1, 2019, 10:18am UTC](https://meta.discourse.org/t/advice-on-writing-ruby-tests-for-plugins/108110/2 "2019-02-01T10:18:57Z")

</div>

> [@kleinfreund](#):
>
> `bundle exec rake plugin:spec["disraptor"]` : Errors with
> 
> ```plaintext
> zsh: no matches found: plugin:spec[disraptor]
> 
> ```

You need to use the **directory** name for you plugin here. So if it’s under `/plugins/discourse-disraptor`, then you run `bundle exec rake plugin:spec[discourse-distraptor]`

> [@kleinfreund](#):
>
> This makes the method untestable because I would need to test actual plugin data from the store which I cannot rely on being there

Why not just put the data in the database? Before testing the `get_routes` function, run this:

```plaintext
PluginStore.set(MyPlugin::PLUGIN_NAME, 'key', 'valuefortest')

```

The database is cleaned up automatically after each individual test. (tests run in a DB transaction, which is rolled back automatically)

---

<div class="post-metadata">

### Author: ![kleinfreund](https://avatars.discourse-cdn.com/v4/letter/k/a6a055/32.png) [@kleinfreund](https://meta.discourse.org/u/kleinfreund)
#### Post date: [February 1, 2019, 10:21am UTC](https://meta.discourse.org/t/advice-on-writing-ruby-tests-for-plugins/108110/3 "2019-02-01T10:21:46Z")

</div>

> [@david](#):
>
> You need to use the **directory** name for you plugin here.

I do. That’s the plugin’s name and directory name. That command errors as stated.

---

<div class="post-metadata">

### Author: ![david](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/david/32/157490_2.png) [@david](https://meta.discourse.org/u/david)
#### Post date: [February 1, 2019, 10:27am UTC](https://meta.discourse.org/t/advice-on-writing-ruby-tests-for-plugins/108110/4 "2019-02-01T10:27:39Z")

</div>

Interesting… I guess it must be failing on this line

> <https://github.com/discourse/discourse/blob/main/lib/tasks/plugin.rake#L90>

To confirm, your spec file is located at `/plugins/disraptor/spec/lib/route_store_spec.rb`?

How is your development environment configured? Windows / Mac / Linux?

---

<div class="post-metadata">

### Author: ![kleinfreund](https://avatars.discourse-cdn.com/v4/letter/k/a6a055/32.png) [@kleinfreund](https://meta.discourse.org/u/kleinfreund)
#### Post date: [February 1, 2019, 10:30am UTC](https://meta.discourse.org/t/advice-on-writing-ruby-tests-for-plugins/108110/5 "2019-02-01T10:30:46Z")

</div>

> [@david](#):
>
> To confirm, your spec file is located at `/plugins/disraptor/spec/lib/route_store_spec.rb` ?

That’s correct. However, `disraptor` is a symbolic link. Could that be the culprit? I’m using Ubuntu.

Also, note how the error that is produced there reads “No specs found.”, but I am getting “zsh: no matches found”.

---

<div class="post-metadata">

### Author: ![david](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/david/32/157490_2.png) [@david](https://meta.discourse.org/u/david)
#### Post date: [February 1, 2019, 10:41am UTC](https://meta.discourse.org/t/advice-on-writing-ruby-tests-for-plugins/108110/6 "2019-02-01T10:41:48Z")

</div>

> [@kleinfreund](#):
>
> `disraptor` is a symbolic link. Could that be the culprit?

I think you’re right

> <https://stackoverflow.com/questions/357754/can-i-traverse-symlinked-directories-in-ruby-with-a-glob>

Using symlinks for plugins in development seems like a pretty reasonable setup, so I went ahead and added support in [DEV: Allow rake plugin:spec to traverse symlinks · discourse/discourse@dfd63b1 · GitHub](https://github.com/discourse/discourse/commit/dfd63b185f3b5279f49f979638dd17c30431669e)

---

<div class="post-metadata">

### Author: ![kleinfreund](https://avatars.discourse-cdn.com/v4/letter/k/a6a055/32.png) [@kleinfreund](https://meta.discourse.org/u/kleinfreund)
#### Post date: [February 1, 2019, 10:44am UTC](https://meta.discourse.org/t/advice-on-writing-ruby-tests-for-plugins/108110/7 "2019-02-01T10:44:54Z")

</div>

I just tried running `bundle exec rake plugin:spec["poll"]` and that produces the same error. However, the `poll` plugin is not symlinked, so that can’t be quite right, or can it?

The piece of code you linked to is also not executed when running `bundle exec rake plugin:spec["poll"]`.

Comparing with the other command: `bundle exec rake plugin:spec poll` produces the same error in the unrelated plugin as stated in the original post.

---

<div class="post-metadata">

### Author: ![david](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/david/32/157490_2.png) [@david](https://meta.discourse.org/u/david)
#### Post date: [February 1, 2019, 10:57am UTC](https://meta.discourse.org/t/advice-on-writing-ruby-tests-for-plugins/108110/8 "2019-02-01T10:57:14Z")

</div>

To be sure we’re looking at the correct part of the code, can you try running `rails c` and then

```plaintext
Dir.glob("./plugins/poll/spec/**/*_spec.rb")

```

---

<div class="post-metadata">

### Author: ![kleinfreund](https://avatars.discourse-cdn.com/v4/letter/k/a6a055/32.png) [@kleinfreund](https://meta.discourse.org/u/kleinfreund)
#### Post date: [February 1, 2019, 12:01pm UTC](https://meta.discourse.org/t/advice-on-writing-ruby-tests-for-plugins/108110/9 "2019-02-01T12:01:24Z")

</div>

> [@david](#):
>
> Dir.glob(“./plugins/poll/spec/\*\*/\*\_spec.rb”)

That produces the correct output:

```plaintext
[1] pry(main)> Dir.glob("./plugins/poll/spec/**/*_spec.rb")
=> ["./plugins/poll/spec/lib/polls_validator_spec.rb",
 "./plugins/poll/spec/lib/polls_updater_spec.rb",
 "./plugins/poll/spec/lib/pretty_text_spec.rb",
 "./plugins/poll/spec/lib/new_post_manager_spec.rb",
 "./plugins/poll/spec/db/post_migrate/migrate_polls_data_spec.rb",
 "./plugins/poll/spec/integration/poll_endpoints_spec.rb",
 "./plugins/poll/spec/controllers/posts_controller_spec.rb",
 "./plugins/poll/spec/controllers/polls_controller_spec.rb",
 "./plugins/poll/spec/requests/users_controller_spec.rb",
 "./plugins/poll/spec/jobs/regular/close_poll_spec.rb"]

```

Same for my plugin, by the way:

```plaintext
[2] pry(main)> Dir.glob("./plugins/disraptor/spec/**/*_spec.rb")
=> ["./plugins/disraptor/spec/lib/route_store_spec.rb"]

```

---

<div class="post-metadata">

### Author: ![david](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/david/32/157490_2.png) [@david](https://meta.discourse.org/u/david)
#### Post date: [February 1, 2019, 12:15pm UTC](https://meta.discourse.org/t/advice-on-writing-ruby-tests-for-plugins/108110/10 "2019-02-01T12:15:43Z")

</div>

How about

```plaintext
bundle exec rake "plugin:spec[poll]"

```

That should [stop zsh trying to be clever](https://github.com/robbyrussell/oh-my-zsh/issues/31)

---

<div class="post-metadata">

### Author: ![kleinfreund](https://avatars.discourse-cdn.com/v4/letter/k/a6a055/32.png) [@kleinfreund](https://meta.discourse.org/u/kleinfreund)
#### Post date: [February 1, 2019, 12:29pm UTC](https://meta.discourse.org/t/advice-on-writing-ruby-tests-for-plugins/108110/11 "2019-02-01T12:29:32Z")

</div>

That’s it! I updated the original post to include this information. You might also want to revert the change in [DEV: Allow rake plugin:spec to traverse symlinks · discourse/discourse@dfd63b1 · GitHub](https://github.com/discourse/discourse/commit/dfd63b185f3b5279f49f979638dd17c30431669e) as traversal of symbolic links works already, right?

* * *

Regarding the testability question, I will clear the database in the tests which will not mess with the database from the development environment because all transactions will be rolled back.

---

<div class="post-metadata">

### Author: ![david](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/david/32/157490_2.png) [@david](https://meta.discourse.org/u/david)
#### Post date: [February 1, 2019, 12:39pm UTC](https://meta.discourse.org/t/advice-on-writing-ruby-tests-for-plugins/108110/12 "2019-02-01T12:39:44Z")

</div>

> [@kleinfreund](#):
>
> I will clear the database in the tests

This should all be handled automatically. The test environment uses a separate database, and each test is run inside a transaction (which is never committed to the DB).

---

<div class="post-metadata">

### Author: ![kleinfreund](https://avatars.discourse-cdn.com/v4/letter/k/a6a055/32.png) [@kleinfreund](https://meta.discourse.org/u/kleinfreund)
#### Post date: [February 1, 2019, 12:49pm UTC](https://meta.discourse.org/t/advice-on-writing-ruby-tests-for-plugins/108110/13 "2019-02-01T12:49:49Z")

</div>

Ah, thank your for clearing that up. My `RAILS_ENV` was set to development, so the tests were running in development mode, too. After unsetting that, it uses the test environment by default. If one wants to enforce a test environment for the tests, they can run this:

```sh
RAILS_ENV=test bundle exec rake plugin:spec["my-plugin-dir"]

```

---

<div class="post-metadata">

### Author: ![sam](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/sam/32/102149_2.png) [@sam](https://meta.discourse.org/u/sam)
#### Post date: [February 4, 2019, 12:08am UTC](https://meta.discourse.org/t/advice-on-writing-ruby-tests-for-plugins/108110/14 "2019-02-04T00:08:32Z")

</div>

`bin/rake autospec` stops a lot of this fuffing around.

Simply run that … then save a spec file in your plugin.

---

<div class="post-metadata">

### Author: ![sam](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/sam/32/102149_2.png) [@sam](https://meta.discourse.org/u/sam)
#### Post date: [May 3, 2019, 3:54am UTC](https://meta.discourse.org/t/advice-on-writing-ruby-tests-for-plugins/108110/15 "2019-05-03T03:54:47Z")

</div>

FYI I fixed symlink traversal in `bin/rake autospec` today which was somewhat tricky but totally worth it.

[https://github.com/discourse/discourse/commit/3b77fb1fb1c5e42c5ee07a97ae4aee49f0edf12f](https://github.com/discourse/discourse/commit/3b77fb1fb1c5e42c5ee07a97ae4aee49f0edf12f)
