[erlang-questions] Unidirectional architectures in Erlang

Jesper Louis Andersen jesper.louis.andersen@REDACTED
Fri Aug 31 21:33:01 CEST 2018

QuickCheck has eqc_temporal (which is a temporal monad). I don't think
proper currently implements the interface, but it isn't too hard to write
it yourself if you want to attack the problem.

You generate random commands like in a statem model.
The system-under-test (SUT) generates trace events.
You stuff those trace events into eqc_temporal or equivalent.
You ask properties of the eqc_temporal trace representation, failing the
test if the rules are broken.

On Fri, Aug 31, 2018 at 9:29 PM Rodrigo Stevaux <roehst@REDACTED> wrote:

> This brings the question, is there a library for writing temporal
> properties for testing with quickcheck or proper? I mean properties that
> say something about the sequence of trace messages and not about the
> contents of the list of trace mssages for example.
> Em sex, 31 de ago de 2018 às 16:24, Jesper Louis Andersen <
> jesper.louis.andersen@REDACTED> escreveu:
>> Hi,
>> I've used the sys module more than once, in both debugging and testing.
>> It is useful, also because you can use sys:log/2,3 to have a trace log of a
>> running process and inspect it later.
>> Another approach I've used is to add trace messages to a system. A module
>> defines this function:
>> report_event(_DetailLevel, _From, _To, _Label, _Contents) ->
>> hopefully_traced.
>> And you call it in your system. Now, you can attach a tracer to this call
>> in tests and verify the trace you get is what you expect. This allows you
>> to "see inside" your system and verify its behavior. More advanced
>> solutions involves rewriting traces into the notion of a temporal monad and
>> then asking questions on the trace for correctness.
>> Yet another approach is to rewrite your code into a computational (pure)
>> part which sets up a set of actions but has no effect, and an effectful
>> part which runs said actions. This allows you to scrutinize the actions
>> without having to bind your system up. Look up, e.g., the Elm architecture
>> for this approach. The basic idea is that of a free monad: rather than
>> running the program, return a command set which can be interpreted either
>> as a test (where the effects are logged) or as a real system (where the
>> effects are run). We do this at $WORK, which means we can test all of our
>> stack without ever having to run the system as a whole in unit tests. In
>> fact, we don't even need a database, or supervisor tree, since we just
>> simulate the universe around a process. Integration tests are run later via
>> a QuickCheck like tool written by Martin Gausby - treating the system as a
>> black box and poking it from the outside to verify we can glue things
>> together as expected.
>> On Fri, Aug 31, 2018 at 7:07 PM Rodrigo Stevaux <roehst@REDACTED> wrote:
>>> yes, we fundamentally are trying to do integration testing.
>>> unit testing process communication pairwise by sending a message to the
>>> parent process is something we tried to do and it worked reasonably well.
>>> but we want to know that the whole composition of processes works well.
>>> the challenge we found on that approach is that the processes have names
>>> and we would have to find a way to inject the pid of the "next" process in
>>> the chain and make it the test process during testing and other process
>>> during production (which can be done with a little bit of instrumentation
>>> and conditional compiling -- we are on Elixir actually).
>>> is using the "sys" module a regular practice?
>>> thanks for the reply.
>>> Em qui, 30 de ago de 2018 às 20:33, Fred Hebert <mononcqc@REDACTED>
>>> escreveu:
>>>> On 08/30, Rodrigo Stevaux wrote:
>>>> >Message comes in, logic applies, message goes out.
>>>> >The generic servers are very easy to test in a pure fashion: just test
>>>> the
>>>> >return values of handle_call for a given state.
>>>> >
>>>> That can be done as a regular unit test, yes.
>>>> >But:
>>>> >- unit testing should test that the unit under test forwards a message
>>>> to a
>>>> >given address (and that is not reflected on the handle_call return
>>>> value)
>>>> Aside from using mocks to know that the proper function calls have
>>>> taken
>>>> place, you can't easily test the forwarding of messages since that
>>>> would
>>>> imply side-effects turning your unit tests into integration tests.
>>>> >- doing the integration testing of a "pipeline" of process involves
>>>> testing
>>>> >that ultimately a message gets to the last process.
>>>> >
>>>> Yes and no. You can test that each element of the chain properly
>>>> forwards data to the right destination. You can do that if you make the
>>>> endpoint/address/destination for each forwarded message parametrizable
>>>> or configurable. Forward the data to the test process instead to
>>>> confirm
>>>> that the right side-effect has taken place.
>>>> This lets you test each section of the chain in isolation; then if all
>>>> sections are well-behaved, you can infer that the whole chain should
>>>> behave well. You can confirm that with a more naive end-to-end test,
>>>> knowing that individual components are tested more thoroughly.
>>>> >Given the maturity of Erlang, I'd expect to promptly find solutions to
>>>> this
>>>> >case.
>>>> On top of the techniques above, you can try using the `sys' module to
>>>> introspect all OTP behaviours and look at their transitions as a
>>>> neutral
>>>> observer:
>>>>     1> sys:get_status(disk_log_server).
>>>>     {status,<0.75.0>,
>>>>             {module,gen_server},
>>>>             [[{<0.76.0>,'$#group_history'},
>>>>               {'$initial_call',{disk_log_server,init,1}},
>>>>               {'$ancestors',[kernel_safe_sup,kernel_sup,<0.45.0>]}],
>>>>              running,<0.66.0>,[],
>>>>              [{header,"Status for generic server disk_log_server"},
>>>>               {data,[{"Status",running},
>>>>                      {"Parent",<0.66.0>},
>>>>                      {"Logged events",[]}]},
>>>>               {data,[{"State",{state,[]}}]}]]}
>>>>     2> P = self(),
>>>>     2> sys:install(
>>>>     2>   disk_log_server,
>>>>     2>   {fun(_Acc, Event, State) -> P ! {trace, Event, State} end,
>>>>     2>    nodata}
>>>>     2> ).
>>>>     ok
>>>>     3> disk_log_server ! fake_data.
>>>>     fake_data
>>>>     4> flush().
>>>>     Shell got {trace,{in,fake_data},disk_log_server}
>>>>     Shell got {trace,{noreply,{state,[]}},disk_log_server}
>>>>     ok
>>>> Those won't let you see arbitrary calls being made, but if you have a
>>>> process chain A -> B -> C, then you can, by looking at the traces of
>>>> all
>>>> three processes, track the history of a call and the consequences they
>>>> have.
>>>> The sys module is full of really cool functionality few people know
>>>> about, and that can make live debugging, but also testing much simpler.
>>>> >
>>>> >I haven't found a nice solution yet, so I suppose I am using OTP in a
>>>> wrong
>>>> >way (maybe it's not a good fit for my project), or I am choosing the
>>>> wrong
>>>> >architecture, or that I am missing key knowledge about how to test
>>>> things
>>>> >in Erlang.
>>>> There aren't enough details to know at this point. I frequently just
>>>> use
>>>> `meck' (https://github.com/eproxus/meck) as a library, which lets you
>>>> replace arbitrary function calls through hot code loadig, get traces
>>>> and
>>>> counts of all calls and values returned of unmodified code, and so on.
>>>> If what you're looking for is a way to track side-effects in a very
>>>> whitebox manner, meck is hard to beat.
>>>> >
>>>> >Can anyone shed some light on this questions? Thanks in advance!
>>>> please provide more details about the nature of the side-effects you
>>>> are
>>>> trying to observe in a unit test. My default reflex would be to say
>>>> that
>>>> the moment you're testing side-effects, you are doing integration
>>>> testing.
>>>> Regards,
>>>> Fred.
>>> _______________________________________________
>>> erlang-questions mailing list
>>> erlang-questions@REDACTED
>>> http://erlang.org/mailman/listinfo/erlang-questions
>> --
>> J.

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://erlang.org/pipermail/erlang-questions/attachments/20180831/ec96924e/attachment.htm>

More information about the erlang-questions mailing list