User Manual - gsi-upm/BeastTool GitHub Wiki

Introduction

This appendix is a manual with detailed information about how to configure Beast Tool. But the main information source should be the paper published in: http://scholar.google.es/citations?view_op=view_citation&hl=es&user=mT3KgXUAAAAJ&citation_for_view=mT3KgXUAAAAJ:Tyk-4Ss8FVUC

Once you have read that paper, you can understand better this wiki.

This manual has the following sections:

0. Beast Test Case

The most relevant class for a user of Beast Tool (i.e. for a tester that uses Beast Tool to test his/her system) is the BeastTestCase class. Any requirement processed by Beast Tool is translated to a test case with three methods that the tester must implement. The structure of any BeastTestCase is the following:

  • setup(): this method must start the agents or mock agents required to execute the test.
  • launch(): this method must generated an event (send a message, change a belief, etc.) to start the tests.
  • verify(): this method must check if the final state is the expected one.

More methods appear in the generated BeastTestCases, but the tester does not need to change anything there. These test cases are generated when the Reader class (exposed in the following sections) is executed with the proper configuration.

1. Beast Tool Execution

The main class used by a user of Beast Tool is the Reader class.

es.upm.dit.gsi.beast.reader.Reader.java

This class accepts two configuration files. The first one is to configure Beast Tool and the second one is a standard Java logging properties file.

Beast Configuration file

This file is a standard Java properties file and Beast Tool check the following properties:

  • srcTestRootFolder: that is the folder where all test classes are stored. Tipically: src/test/java
  • requirementsFolder: that is the folder where all requirements are stored in ".story". Only one ".story" file can be passed here as property, if you want to process only one story.
  • storiesPackage: that is the package where all test classes will be generated.
  • specificationPhase: that is the package where the specification phase is defined. It can be: "MAS" or "SYSTEM" to parse "AgentStories" or "UserStories" respectively.
  • caseManagerPackage: that is the package where the "AgentStoriesManager" or the "UserStoriesManager" is created.
  • MASPlatorm: The name of any supported MAS platform. For example: JADE or JADEX (ignoring cases). This property is ignored if the "specificationPhase" is "SYSTEM".

Here, an example is attached:

srcTestRootFolder=src/test/java
storiesPackage=beast.tutorial.stories.mas
requirementsFolder=src/test/resources/stories/mas/
caseManagerPackage=beast.tutorial.manager
specificationPhase=MAS
MASPlatform=jade

This text must be stored in a properties file, for example: "my-conf-beast-tool.properties"

The first property indicates the folder where the tests will be created, the second property assigns the platform to be used, the third property specifies the package name of the new tests, the forth property indicates the file where is disposed the requirements written by the stakeholder and the last property is used to designate the path where the CaseManager file will be created.

Logging properties

This file specifies the level of the logs to be displayed in console and how to deal with them. Here you can find an example:

handlers = java.util.logging.ConsoleHandler
.level=ALL
java.util.logging.ConsoleHandler.level=INFO
java.util.logging.ConsoleHandler.formatter=java.util.logging.SimpleFormatter

1.1 Beast Reader

This class must be executed to analyse all requirements specified in .story format. You can configure your pom.xml to execute this class during the generate-test-sources maven phase (See the tutorial) or you can execute from console with:

java -jar beast-tool-0.9.8.jar <path to beast config file> <path to logging config file (optional)>

Note: To execute Beast Tool in console, you must add all dependencies to your path (and there are a lot of them...). So, we recommend you to follow the indications exposed in the Tutorial.

1.2 Story files format

Any story file is a plain text with the following structure:

Story: ...
As a ...
I want to ...
So that ...
And ...

Scenario: ...
Given ...
When ...
And ...
Then ...

Scenario: ...
Given ...
When ...
Then ...
  • "Story" lines must start with: "Story: ", "Story - " or "Story ".

  • The same for "Scenario" lines.

  • "And" lines are added to the previous line. For example:

      Given X
      And Y
    

is parsed as "Given X and Y". With the exceptions of "Story" and "Scenario" lines. They must be written in one line. Since these lines are the title of the story or the scenario, we recommend to use only a few words.

2. Beast Mock Agents

Beast Tool offers several mock agents developed for JADE and JADEX.

As there is not exactly a Java class that we can mock to emulate the behaviour of that agents. We have a configuration class that we mock every time we want to configure a Mock Agent.

We have three different Mock Agents:

  • Listener: only receives messages.
  • Repository: receives and responses messages.
  • Bridge: receives messages from an agent and sends other messages to a third agent.

So, we configure those behaviours with two classes:

es.upm.dit.gsi.beast.mock.common.MockConfiguration.java
es.upm.dit.gsi.beast.mock.common.AgentBehaviour.java

MockConfiguration is used to define how the agent must be registered in the DF service or its name.

AgentBehaviour is the class that we mock every time we start a mock agent.

There is other important class with constants that we use to ensure that there is no typos in the path and/or the name of the agents:

es.upm.dit.gsi.beast.mock.common.Definitions.java

It can be used in the setup() method of any BeastTestCase as follows:

    //BridgeAgent configuration
    AgentBehaviour myMockedBehaviour =  mock(AgentBehaviour.class);
    MockConfiguration mock_configuration = new MockConfiguration();
    mock_configuration.setDFServiceName("myService");
    mock_configuration.setBehaviour(myMockedBehaviour);

    when(myMockedBehaviour.processMessage(eq(SFipa.INFORM), eq("send")))
        .thenReturn("listen_service", SFipa.INFORM, "Message to the listener agent");   

    MockManager.startMockJadexAgent("BridgeAgent",Definitions.JADEX_BRIDGE_MOCK_PATH,mock_configuration,this);

The most important part of the previous path is the when(X).thenReturn(Y). That is the standard Mockito structure to mock any Java object. Every time that you call to myMockedBehaviour.processMessage() with the specified arguments, that object will return one of the answer defined in the thenReturn method. For further reading about Mockito, see Mockito project in Google Code or Github.

https://code.google.com/p/mockito/

https://github.com/mockito/mockito

As it was mentioned before, there are three Mock Agents developed in Beast Tool for JADE and JADEX. Their configurations are presented below:

Note: you can find some examples in beast-tutorial project or in the tests of beast-tool project.

Listner Mock Agent

This agent is registered in the DF and listens/receives any message.

	AgentBehaviour myMockedBehaviour =   mock(AgentBehaviour.class);
    MockConfiguration mock_configuration = new MockConfiguration();
    mock_configuration.setDFServiceName(<service to register the agent in DF>);
    mock_configuration.setBehaviour(myMockedBehaviour);
    MockManager.startMockJadexAgent(<name of the agent>,<path to the agent definition class or xml>,this);

There parameters must be changed:

  • <service to register the agent in DF>: it could be "report-service"
  • <name of the agent>: it could be "myFriendAgent"
  • <path to the agent definition class or xml>: it could be
    • "Definitions.JADEX_LISTENER_MOCK_PATH" or
    • "Definitions.JADE_LISTENER_MOCK_PATH"

To sum up, you only have to define which name must be registered in DF.

This agent stores a belief to count how many messages have been received. So, you can check it in the verify() method of any test case.

checkAgentsBeliefEquealsTo(<agent name>, Definitions.RECEIVED_MESSAGE_COUNT, 2);

Of course, this agent can be more complex and more beliefs can be stored, but we offer simple mock agents to test communication among agents under testing. So, if more complex mock agents are required, the developer/tester must implement them.

Repository Mock Agent

This agent is registered in the DF and replies any message with a given performative.

	AgentBehaviour myMockedBehaviour = mock(AgentBehaviour.class);
	when(myMockedBehaviour.processMessage(eq(<performative>),
					eq(<sender agent name>),
					eq(<msg content>))).thenReturn(<reply msg content>);
	MockConfiguration mock_configuration = new MockConfiguration();
	mock_configuration.setDFServiceName(<service to register the agent in DF>);
	mock_configuration.setBehaviour(myMockedBehaviour);
	MockManager.startMockJadexAgent(<name of the agent>,<path to the agent definition class or xml>, mock_configuration,
			this);

Some of these parameters are equals to the previous mock agent, the new ones are the followings:

  • <performative>: the performative of the message received by the agent. For example: SFipa.REQUEST (for JADEX) or ACLMessage.REQUEST (for JADE).
  • <sender agent name>: the name of the agent that sends the message.
  • <msg content>: the content of the received message.
  • <reply msg content>: this agent replies the received message with an FIPA-INFORM message with the content provided in this parameter.

Bridge Mock Agent

This agent is registered in the DF and when it receives a message, it sends a new message to a third agent.

    AgentBehaviour myMockedBehaviour = mock(AgentBehaviour.class);
    when(myMockedBehaviour.processMessage(
                    eq(eq(<performative>),
                    eq(<msg content>))).thenReturn(<receiver agent name>,
           <performative to send>,<content to send>);
    MockConfiguration mock_configuration = new MockConfiguration();
    mock_configuration.setDFServiceName(<service to register the agent in DF>);
    mock_configuration.setBehaviour(myMockedBehaviour);
    MockManager.startMockJadeAgent(<name of the agent>,<path to the agent definition class or xml>, mock_configuration, this);

2.1 JADE Mock Agents

When you are configuring JADE Mock Agents, you have to take care with these points:

  • Performatives in JADE are defined in ACLMessage class. So, you can use constants, such as: ACLMessage.REQUEST or ACLMessage.INFORM.
  • Agent class must be specified as a String. For example: "es.upm.dit.gsi.beast.mock.jade.bridgeMock.BridgeMockAgent". But we use constants defined in Defitions class (es.upm.dit.gsi.beast.mock.common.Definitions.java). So, you can use: Definitions.JADE_LISTENER_MOCK_PATH or Definitions.JADE_REPOSITORY_MOCK_PATH.

2.2 JADEX Mock Agents

When you are configuring JADEX Mock Agents, you have to take care with these points:

  • Performatives in JADE are defined in SFipa class. So, you can use constants, such as: SFipa.REQUEST or SFipa.INFORM.
  • Agent class must be specified as a String. For example: "es.upm.dit.gsi.beast.mock.jadex.bridgeMock.BridgeMock.agent.xml". But we use constants defined in Defitions class (es.upm.dit.gsi.beast.mock.common.Definitions.java). So, you can use: Definitions.JADEX_LISTENER_MOCK_PATH or Definitions.JADEX_REPOSITORY_MOCK_PATH.

3 Testing agents with Beast

JADE and JADEX are quite similar in the scope (MAS platforms), but really different in the implementation. So, there are some differences testing the agents.

3.1 JADE agents

Since JADE 4.0 does not offer any external access to the agents running in the platform, we use a Singleton (http://en.wikipedia.org/wiki/Singleton_pattern) object to get external access: JadeAgentInstrospector

Check: JadeAgentIntrospector javadoc in http://gsi-upm.github.io/BeastTool/apidocs/es/upm/dit/gsi/beast/platform/jade/JadeAgentIntrospector.html.

So, we have to do a few additions in the agent code to be able to get external access.

Note: you can find some examples of this additions in:

beast-tutorial/src/main/java
	beast.tutorial.jade.agent
		HelpDeskAgent.java
		RecorderAgent.java
		ReporterAgent.java

The first thing we must do in the Agent Under Testing (AUT) is register it in the JadeAgentIntrospector. In the setup() agent method, add this line:

JadeAgentIntrospector myIntrospector = JadeAgentIntrospector.getMyInstance((Agent) this);

You can store this introspector as an attribute, as it will be used later.

To get external access to a belief and to check it with checkAgentsBeliefEquealsTo() method, you must store it in the introspector.

myIntrospector.storeBeliefValue(<agent object>, <belief_name>, <belief_value>);

For example:

myIntrospector.storeBeliefValue(this, "createdIssueReport", true);

To get access to a belief modified externally:

Object belief_value = myIntrospector.getBeliefBase(<agent object>).get(<belief_name>));

For example:

CallQueue queue = myIntrospector.getBeliefBase(this).get("queue"));

3.2 JADEX agents

As JADEX2.0 offers external access capabilities, no additions or modifications must be done in any JADEX agent.

⚠️ **GitHub.com Fallback** ⚠️