Hi Jose,

Good point! I actually didn't pay much attention to the behavior testing 
part because the code that was pointing out the use case was the one that 
was commented out. So, here goes another try. What do you think about the 
following code?

*By the way, I really appreciate you taking out the time to look at the 
code. I know you have a packed schedule. :)*

Best,
Adi

CODE SNIPPET:
```ex
defmodule Behavior do
  defmacro __using__(options) do
    fun = Keyword.get(options, :fun, :fun)

    quote do
      def __some_function__, do: :something
      def __some_other_function__, do: :something
      def unquote(fun)(), do: :fun
    end
  end
end

defmodule TestSubject1 do
  use Behavior, fun: :fun1
end

defmodule TestSubject2 do
  use Behavior, fun: :fun2
end

defmodule TestSubject3 do
  use Behavior
end

defmodule TestSubject4 do
  use Behavior, fun: :fun4
end

## Tests
ExUnit.start()

# This test should sufficiently test Behavior module's functions and use 
cases
defmodule BehaviorTest do
  use ExUnit.Case

  defmodule TestWithFun do
    use Behavior, fun: :test
  end

  defmodule TestWithoutFun do
    use Behavior
  end

  describe "__using__/1" do
    test "defines static functions along with `fun/0 `is no fun provided" do
      assert TestWithoutFun.__some_function__() == :something
      assert TestWithoutFun.__some_other_function__() == :something
      assert TestWithoutFun.fun() == :fun
    end

    test "defines static functions along with `test/0 ` when fun is :test" 
do
      assert TestWithFun.__some_function__() == :something
      assert TestWithFun.__some_other_function__() == :something
      assert TestWithFun.test() == :fun
    end
  end
end

defmodule TestSubject1Test do
  use ExUnit.Case

  # This test is re-testing `Behavior.__using__/1` instead of just testing
  # its usage
  describe "uses Behavior" do
    test "defines static functions along with `fun1/0`" do
      assert TestSubject1.__some_function__() == :something
      assert TestSubject1.__some_other_function__() == :something
      assert TestSubject1.fun1() == :fun
    end
  end

  # `@__using__` attribute will allow us to do something like this, instead
  # of testing `Behavior.__using__/1` again.
  # describe "use Behavior" do
  #   test "uses Behavior with fun option" do
  #     uses = TestSubject1.__info__(:attributes)[:__using__]
  #
  #     assert {Behavior, [fun: :fun1]} in uses
  #   end
  # end
end

## --- More tests for TestSubject2, TestSubject3 and TestSubject4
```

Now that we have tested how `Behavior.__using__/1` behaves (by calling the 
actual functions), testing whether `TestSubject1` has correct attributes 
set should be sufficient, right?
On Monday, 8 March 2021 at 15:58:11 UTC-5 José Valim wrote:

> Hi Adi,
>
> I don’t think this is a good idea. All of your tests are testing that it 
> defined a function or uses something but it really doesn’t test that any of 
> that *behaves* as you would want.
>
> Since we don’t want to promote such tests, it is not something we see in 
> the language.
>
> Thank you, 
>
> On Mon, Mar 8, 2021 at 21:53 Adi <[email protected]> wrote:
>
>> Hi Jose, 
>>
>> Sorry if I'm not doing a good job explaining it. I'll share some code 
>> below.
>>
>> Hi Wojtek, Great idea using compile-time tracers! Unfortunately, I don't 
>> see them capturing information related to the arguments being passed to the 
>> macro. If there's a way to do that, it would satisfy my use case.
>>
>> Either way, I have shared the code snippet below. Let me know what both 
>> of your thoughts are.
>>
>> Best,
>> Adi
>>
>> CODE SNIPPET:
>>
>> ```ex
>> defmodule Behavior do
>>   defmacro __using__(options) do
>>     fun = Keyword.get(options, :fun, :fun)
>>
>>     quote do
>>       def __some_function__, do: :something
>>       def __some_other_function__, do: :something
>>       def unquote(fun)(), do: :fun
>>     end
>>   end
>> end
>>
>> defmodule TestSubject1 do
>>   use Behavior, fun: :fun1
>> end
>>
>> defmodule TestSubject2 do
>>   use Behavior, fun: :fun2
>> end
>>
>> defmodule TestSubject3 do
>>   use Behavior
>> end
>>
>> defmodule TestSubject4 do
>>   use Behavior, fun: :fun4
>> end
>>
>> ## Tests
>> ExUnit.start()
>>
>> # This module should sufficiently test Behavior module's functions and 
>> use cases
>> defmodule BehaviorTest do
>>   use ExUnit.Case
>>
>>   defmodule TestWithFun do
>>     use Behavior, fun: :test
>>   end
>>
>>   defmodule TestWithoutFun do
>>     use Behavior
>>   end
>>
>>   describe "__using__/1" do
>>     test "defines static functions along with `fun/0 `is no fun provided" 
>> do
>>       assert {:__some_function__, 0} in 
>> TestWithoutFun.__info__(:functions)
>>       assert {:__some_other_function__, 0} in 
>> TestWithoutFun.__info__(:functions)
>>       assert {:fun, 0} in TestWithoutFun.__info__(:functions)
>>     end
>>
>>     test "defines static functions along with `test/0 ` when fun is 
>> :test" do
>>       assert {:__some_function__, 0} in TestWithFun.__info__(:functions)
>>       assert {:__some_other_function__, 0} in 
>> TestWithFun.__info__(:functions)
>>       assert {:test, 0} in TestWithFun.__info__(:functions)
>>     end
>>   end
>> end
>>
>> defmodule TestSubject1Test do
>>   use ExUnit.Case
>>
>>   # This test is re-testing `Behavior.__using__/1` instead of simply 
>> testing
>>   # its usage. 
>>   describe "uses Behavior" do
>>     test "defines static functions along with `fun1/0`" do
>>       assert {:__some_function__, 0} in TestSubject1.__info__(:functions)
>>       assert {:__some_other_function__, 0} in 
>> TestSubject1.__info__(:functions)
>>       assert {:fun1, 0} in TestSubject1.__info__(:functions)
>>     end
>>   end
>>
>>   # `@__using__` attribute will allow us to do something like this, 
>> instead
>>   # of testing `Behavior.__using__/1` again.
>>   # describe "use Behavior" do
>>   #   test "uses Behavior with fun option" do
>>   #     uses = TestSubject1.__info__(:attributes)[:__using__]
>>   #
>>   #     assert {Behavior, [fun: :fun1]} in uses
>>   #   end
>>   # end
>> end
>>
>> ## --- Similar tests for TestSubject2, TestSubject3 and TestSubject4
>> ```
>>
>>
>>
>> -- 
>> You received this message because you are subscribed to the Google Groups 
>> "elixir-lang-core" group.
>> To unsubscribe from this group and stop receiving emails from it, send an 
>> email to [email protected].
>>
> To view this discussion on the web visit 
>> https://groups.google.com/d/msgid/elixir-lang-core/6fe63cce-2b4c-4af9-a9af-4e473f63533an%40googlegroups.com
>>  
>> <https://groups.google.com/d/msgid/elixir-lang-core/6fe63cce-2b4c-4af9-a9af-4e473f63533an%40googlegroups.com?utm_medium=email&utm_source=footer>
>> .
>>
>

-- 
You received this message because you are subscribed to the Google Groups 
"elixir-lang-core" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/elixir-lang-core/51f9ff7a-7a4f-46f2-a19e-fc21d18826a5n%40googlegroups.com.

Reply via email to