antonmi / espec

Elixir Behaviour Driven Development
Other
808 stars 62 forks source link

behaviour of `subject!` feels broken #271

Closed janpieper closed 6 years ago

janpieper commented 6 years ago

Have a look at this simple spec file:

defmodule ExampleSpec do
  use ESpec

  before do: IO.inspect("A")

  subject! do: IO.inspect("SUBJECT")

  context do
    before do: IO.inspect("B")

    context do
      before do: IO.inspect("C")

      it do: IO.inspect("TEST")
    end
  end
end

Actual

  1. A
  2. SUBJECT
  3. B
  4. C
  5. TEST

Expected

  1. A
  2. B
  3. C
  4. SUBJECT
  5. TEST

I would expect that ESpec runs all relevant before blocks, before it runs the subject...

To get the expected behaviour, i need to write the test like this:

defmodule ExampleSpec do
  use ESpec

  before do: IO.inspect("A")

  subject do: IO.inspect("SUBJECT") # changed `subject!` to `subject`

  context do
    before do: IO.inspect("B")

    context do
      before do: IO.inspect("C")

      it do
        subject() # explicit call of `subject()`
        IO.inspect("TEST")
      end
    end
  end
end

That's fine for such a simple case, but if you have a lot more test cases and contexts, that gets really ugly...

Is there a simple workaround or an undocumented way to get my expected behaviour without having to call subject() in each test?

antonmi commented 6 years ago

Hi, @janpieper ! Sorry for the late response. This is an expected behavior. Please, see let and subject section. let and subject are not evaluated until you call them. The bang versions are evaluated as if they are before callbacks.

sascha-wolf commented 6 years ago

I agree, this is expected behaviour but does it have to be? I can see how this might be confusing for an uninitiated, so while this technically is not an issue it certainly is a worthwhile suggestion for improvement.

Anton Mishchuk notifications@github.com schrieb am So., 27. Mai 2018, 21:42:

Hi, @janpieper https://github.com/janpieper ! Sorry for the late response. This is an expected behavior. Please, see let and subject https://github.com/antonmi/espec#let-and-subject section. let and subject are not evaluated until you call them. The bang versions are evaluated as if they are before callbacks.

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/antonmi/espec/issues/271#issuecomment-392361032, or mute the thread https://github.com/notifications/unsubscribe-auth/AChmSjfc79FZy-NFASOzhbyVB5yyaegYks5t2wGsgaJpZM4T-DG_ .

antonmi commented 6 years ago

Hi, Zeeker! This behavior is borrowed from Ruby RSpec library and seems natural for people with Ruby background. But I agree that it is not very intuitive.

The original idea behind 'let' ('subject' is the same) is to create named function with memoizable values. And, as a function, 'let' is not evaluated until you call it. The idea of band versions is to create a shortcut for smth like:

let :a, do: 1
before do: a()

This is useful when you wanna evaluate 'let' before your specs as 'before' callback.

Thank you, guys, for the issue. I should definitely add more description to the Readme.

antonmi commented 6 years ago

@janpieper , @Zeeker , I've changed description in the Readme a little bit. Please review if it makes sense. Be free to create PR with even more detailed explnation