I guess it depends a bit on how advanced your server's state is. In the adder example above, it's easy enough to test via the public interface. However, if you want to test edge cases on the state, it can be a lot easier to be able to just pass in the state you want to begin from, than to start up a gen_server and send it the right sequence of commands to bring it to that state.<div>
<br></div><div>I've been working on tests of a connection pool system, and it's a lot easier to just test that handle_call, handle_info et. al. do the right thing given an input state and a command, than it is to set up the gen_server and provoke the right kind of errors via mocking.<br>
<div><br></div><div>Another way is to make the handle_call etc. simply destructure their input and pass on to other functions that actually perform the operations. Then you can unit test those functions separately. This might help avoid some of the brittleness mentioned in regards to changing the formats of calls or state.</div>
<div><br></div><div>/Daniel<br><div><br><div class="gmail_quote">On 14 August 2012 10:11, Steve Strong <span dir="ltr"><<a href="mailto:steve@srstrong.com" target="_blank">steve@srstrong.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div style="word-wrap:break-word">I would much prefer the latter - i.e., to test the public interface. Otherwise you will end up with brittle tests that become a maintenance headache. That said, I have had occasions where some functionality was much easier to test through the internal implementation rather than through the public API, so I think it depends to a degree on the context.<div>
<br></div><div>Cheers,</div><div><br></div><div>Steve<br><div><br><div>
<div><div><div>--------------------------</div><div><font><b>Steve Strong</b></font></div><div><font><b>Director, id3as</b></font></div><div><font><a href="tel:%2B34%20636451137" value="+34636451137" target="_blank">+34 636451137</a></font></div>
<div><font>@srstrong</font></div></div><div><font><br></font></div></div><br>
</div><div><div class="h5">
<br><div><div>On Aug 14, 2012, at 9:57 AM, Jan Vincent Liwanag <<a href="mailto:jvliwanag@gmail.com" target="_blank">jvliwanag@gmail.com</a>> wrote:</div><br><blockquote type="cite"><div style="word-wrap:break-word">
<div>Given the following code:</div><div><br></div><div>adder.erl:</div><div><br></div><div><font face="Courier">start(B) -> gen_server:start(?MODULE, B, []).</font></div><div><font face="Courier">add(Pid, N) -> gen_server:cast(Pid, {add, N}).</font></div>
<div><font face="Courier">get_total(Pid, N) -> gen_server:call(Pid, get_total).</font></div><div><font face="Courier"><br></font></div><div><font face="Courier">init(Total) -> {ok, Total}.</font></div><div><font face="Courier"><br>
</font></div><div><font face="Courier">handle_call(get_total, _From, Total) -> {reply, Total, Total}.</font></div><div><font face="Courier">handle_cast({add, N}, Total) -> {noreply, N+Total).</font></div><div><br></div>
<div><br></div><div>It would be better to have a test such that:</div><div><div><br></div><div><font face="Courier">{ok, P} = adder:start(0),</font></div><div><font face="Courier">adder:add(P, 5),</font></div><div><font face="Courier">adder:add(P, 3),</font></div>
<div><font face="Courier">adder:add(P, 2),</font></div></div><div><font face="Courier">?assertEqual(10, adder:get_running_total()).</font></div><div><br></div><div>Rather than:</div><div><br></div><div><font face="Courier">?assertEqual({noreply, 12}, handle_cast({add, 5}, 7)).</font></div>
<div><font face="Courier">?assertEqual({reply, 100, 100}, handle_call(get_total, somepid, 100)).</font></div><div><br></div><div>For one thing, if I change the gen_server state from an int to a record and fix up the code - the first set of tests should still succeed while the second won't.</div>
<br><div><div>On Aug 14, 2012, at 2:41 PM, Daniel Eliasson wrote:</div><br><blockquote type="cite">It should be easy enough to unit test such things, just run a handle_call with the right arguments, and verify that the output and new state is correct?<div>
<br></div><div>I don't think there's a need to actually start the gen_server itself and unit test the callbacks by going through gen_server:call, if that's what you mean. In what way do you find it to be fragile?<div>
<br></div><div>Best,</div><div>Daniel<br><br><div class="gmail_quote">On 14 August 2012 03:48, Jan Vincent Liwanag <span dir="ltr"><<a href="mailto:jvliwanag@gmail.com" target="_blank">jvliwanag@gmail.com</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div style="word-wrap:break-word"><div>Hi,</div><div><br></div><div>What are your thoughts on unit testing gen_server (or other gen_*) callbacks (handle_call, etc) directly? Is this an ok practice? Or should unit tests test only the public api?</div>
<div><br></div><div>On my end, I find testing gen_server callbacks to be rather fragile. Eager to hear out other thoughts.</div><div><br></div><div>Thanks,</div><br><div>
<span style="text-indent:0px;letter-spacing:normal;font-variant:normal;text-align:-webkit-auto;font-style:normal;font-weight:normal;line-height:normal;border-collapse:separate;text-transform:none;font-size:medium;white-space:normal;font-family:Helvetica;word-spacing:0px"><span style="text-indent:0px;letter-spacing:normal;font-variant:normal;text-align:-webkit-auto;font-style:normal;font-weight:normal;line-height:normal;border-collapse:separate;text-transform:none;font-size:medium;white-space:normal;font-family:Helvetica;word-spacing:0px"><div style="word-wrap:break-word">
<div>Jan Vincent Liwanag</div><div><a href="mailto:jvliwanag@gmail.com" target="_blank">jvliwanag@gmail.com</a></div><div><a href="tel:%2B63%20%28999%29%20888-0247" value="+639998880247" target="_blank">+63 (999) 888-0247</a></div>
</div></span></span>
</div>
<br></div><br>_______________________________________________<br>
erlang-questions mailing list<br>
<a href="mailto:erlang-questions@erlang.org" target="_blank">erlang-questions@erlang.org</a><br>
<a href="http://erlang.org/mailman/listinfo/erlang-questions" target="_blank">http://erlang.org/mailman/listinfo/erlang-questions</a><br>
<br></blockquote></div><br></div></div>
</blockquote></div><br><div>
<span style="border-collapse:separate;font-family:Helvetica;font-style:normal;font-variant:normal;font-weight:normal;letter-spacing:normal;line-height:normal;text-align:-webkit-auto;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px;border-spacing:0px;font-size:medium"><span style="border-collapse:separate;font-family:Helvetica;font-style:normal;font-variant:normal;font-weight:normal;letter-spacing:normal;line-height:normal;text-align:-webkit-auto;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px;border-spacing:0px;font-size:medium"><div style="word-wrap:break-word">
<div>Jan Vincent Liwanag</div><div><a href="mailto:jvliwanag@gmail.com" target="_blank">jvliwanag@gmail.com</a></div><div><a href="tel:%2B63%20%28999%29%20888-0247" value="+639998880247" target="_blank">+63 (999) 888-0247</a></div>
</div></span></span>
</div>
<br></div>_______________________________________________<br>erlang-questions mailing list<br><a href="mailto:erlang-questions@erlang.org" target="_blank">erlang-questions@erlang.org</a><br><a href="http://erlang.org/mailman/listinfo/erlang-questions" target="_blank">http://erlang.org/mailman/listinfo/erlang-questions</a><br>
</blockquote></div><br></div></div></div></div></div></blockquote></div><br></div></div></div>