I had a lot of issues unit testing MASON code but I don't really see any
problem with the way Steppable and SimState operate.
Siggy's right: often you are better off passing all information at
constructor or in a start() method rather than grabbing it from SimState.
But that creates all sorts of other issues. If you realize later on (as it
always happens) that the agent actually needs some more input, you need to
change the interface/constructor of the agent (which is a pain if it's
subclassed or instantiated often) and you also need to straighten out the
initialization sequence between all agents and all inputs.
It also makes the testing clunky as you need to build all sorts of objects
even though you only care about unit testing the interaction between the
agent and one of the inputs.
I don't see the advantage in having to do this (god forbid using a builder
pattern):
Agent agent = new Agent( mock(InterestingInput.class),
mock(UninterestingInput1.class),
mock(UninterestingInput1.class),
....,
mock(UninterestingInputn.class))
agent.step(mock(Simstate.class))
assertEquals(agent.getInterestingOutput(),target)
compared to just stubbing a getter from the SimState
Agent agent = new Agent()
SimState state = mock(Simstate.class);
when(state.getInterestingContext()).thenReturn(mock(InterestingInput.class))
agent.step()
assertEquals(agent.getInterestingOutput(),target)
At least regarding the testing itself.
Am I missing something?
Issues to me always emerge because SimState and all the other MASON objects
tend to access fields directly (state.random or state.schedule) which
screws with mocks big time. But that's just a matter of building a couple
of getters and setters and enforcing your code to use them.
On Fri, Mar 16, 2018 at 9:02 AM Simon Sohrt <[log in to unmask]>
wrote:
> Hi,
>
>
>
> thank you Rob and Siggy for the answers. Here’s what I will do (I’m
> posting this, because it might guide some other newcomers):
>
> I will give my agents only the references they need at construction time
> and then create a Steppable to step my agents (my agents step method will
> not have a parameter and will never have access to SimState). The
> parameters of the contructor will only by interfaces (not actual objects
> themselves. This is done to further decouple the objects in my simulation).
>
> Because construction of the agents is rather complicated, I will use the
> builder-pattern to collect all information that I need for constructing my
> agents. The builder has access to SimState. By using the builder pattern I
> can make sure that my agents are fully initialized after being constructed.
>
>
>
> Best Regards,
>
>
>
> Simon
>
>
>
>
>
>
>
> Rob wrote:
>
>
>
> This is a bit of idle speculation on my part, but having worked on a MASON
> extension and another ABM at this point, I found myself either having to
> use a dependency injection pattern or a singleton pattern so I could expose
> objects that all of the agents eventually needed access to (e.g., random,
> environmental attributes, etc.).
>
> In terms of testing though, if SimState was hidden behind an interface
> (e.g., ISimState) then you could use a mocking pattern and just initialize
> the parts that are relevant to your test. From what I've seen of the MASON
> code it might not be a major undertaking to make that change to the code
> base.
>
> - Rob
>
>
>
> On Thu, Mar 15, 2018 at 4:23 PM, Eric 'Siggy' Scott <[log in to unmask]>
> wrote:
>
> Simon,
>
>
>
> I can't speak to the actual rational behind SimState, but I can say that
> I've had similar frustrations in the past. I do think that the "God
> object" approach is a bit easier for newcomers to learn. It's easier to
> think in terms of an agent that "reaches out into the world and does stuff"
> than an agent that "is handed exactly what it needs and only what it needs
> as references at construction time, and works only with those references to
> affect the world" (which is the approach I naturally gravitate toward).
>
>
>
> But if you aren't careful, boy can it make unit testing frustrating! To
> say nothing of tracking down weird unintended side effects.
>
>
>
> The solution I've settled on is to make sure that my "God object" can
> easily be partially initialized with only the components that are needed to
> provide indirect inputs and outputs to the agent under test. This
> minimizes the need for stubbing and mocking, and arguably isn't any more
> difficult than testing an agent that takes references to data it needs at
> construction time.
>
>
>
> Siggy
>
>
>
>
>
> On Thu, Mar 15, 2018 at 11:28 AM, Simon Sohrt <
> [log in to unmask]> wrote:
>
> I don't have a question about how to use some part of mason, but I am
> rather curious about the reasoning behind the architecture of the interface
> Steppable.
>
> Why was the method step(SimState state) designed to take a parameter?
> If my agents directly implement the interface Steppable, my agents have
> access to all other objects in my simulation which makes my agents hard to
> unit-test (since I have to initialize the 'god-object' SimState to call the
> step-method).
>
> I am aware that I can circumvent this by creating a Steppable as described
> in the manual on page 109:
> Steppable even = new Steppable() { public void step(SimState state) {
> myObject2.foo(); }};
> But isn't this a little bit ugly from a design perspective, because the
> parameter state is completely ignored by myObject2.foo()?
>
> I am also aware that I can use the sim.engine.MethodStep-method to avoid
> passing the SimState, but the manual does not recommend it for good reasons.
>
> The manual also mentions that the Repast-method for stepping agents works
> like the sim.engine.MethodStep-method from Mason, but I recently looked
> into the current version of Repast Simphony 2.5 and Repast uses costume
> annotations @ScheduledMethod(start = 1, interval = 1), to add methods to
> the schedule, which seems to me that this is not a violation of Java
> contracts (as the mason manual claims on page 108). Is the mason manual
> maybe outdated or am I not correctly understanding the critique about the
> way Repast schedules methods?
>
>
>
>
>
> --
>
>
>
> Ph.D student in Computer Science, George Mason University
>
> Web Director, Journal of Mason Graduate Research
>
> http://mason.gmu.edu/~escott8/
>
>
>
|