Activity 19: Test generation for a component
Test generation for a component is restricted to the provided interfaces of a component. Hence, for the vending machine, the tests includes commands and signals of interfaces IUser and IService.
-
Since input values for IService have already been specified in IService.params, it remains to define input values for IUser. In folder IUser, create a file IUser.params (right click on folder, select New > File).
-
Insert the following text in the file:
import "IUser.interface" interface: IUser
After the last line, use content assist CTRL+SPACE and select Autocomplete missing triggers. This leads to a template which requires one or more input values for the command OrderProduct in all relevant states of the interface model. Modify the template using ProductName, so ProductName::WATER, ProductName::JUICE, or ProductName::COLA, simular to IService.params. Note that multiple parameters are allowed. Also observe that nothing has to be specified for the output parameter of InsertCoin.
-
Adapt the project file VendingMachine.prj with the following tasks:
Generate ReachabilityGraph { ReachabilityGraph_VendingMachine for component VendingMachine { max-depth: 3 params: 'IService/IService.params' 'IUser/IUser.params' } } Generate Test { Test_VendingMachine for task ReachabilityGraph_VendingMachine { java: {} } }
-
Note that the depth has been limited to 3 to avoid a large number of tests and a long testing time for the first experiments.
-
Execute the CommaSuite workflow on this project file.
-
Note that an adapter has already been constructed manually in folder src/test.VendingMachine. Observe that in this adapter the CoinChecker is called to set expected return values.
-
Run the generated test cases in src-gen/test.VendingMachine by right clicking on TestCases.java and selecting Run As > JUnit Test.
-
If all tests pass, increase the depth and inspect the results. Depending on the interface model, it is likely that some tests fail. The problem is that the model will usually not model the number of available bottles, so it does not specify the result of the OrderProduct command exactly, that is, when to return DELIVERED and when to return NO_PRODUCTS_AVAILABLE. Two possible solutions:
-
The easiest solution is to weaken the interface model of IUser and use "reply(*)" as result of command OrderProduct when there is enough credit available.
-
Since bottles are removed by OrderProduct of interface IUser and added by LoadProduct of IService, the relation can be expressed in a rather complicated component constraint where a variable of type map keeps track of the number of available products. Initialize this variable such that there are 2 bottles available for each product type, so 2 bottles of water, 2 bottles of juice, and 2 bottles of cola. By means of this variable it can be specified when to return DELIVERED or NO_PRODUCTS_AVAILABLE.
After solving the issue, increase the depth and inspect the results.
-