ERP 2.50:Automated Testing/How to automate a test case
Define what you want to test
The first step is to get a high level definition of the functionality that will be tested.
Please take into account that tests should be simple, independent and stable. And that we try that most of our tests follow the principle described by the GUIUnit concept. So multiple small tests that focus on a single feature of the application are preferred to complex and huge ones that will follow a long flow of interactions.
Document the scenario and execute it manually
There has to be a manual process before trying to automate a test. It's necessary to write down the steps of the test and execute them manually many times.
Document your test following the guidelines described in How to document a test. Follow the documentation by yourself to be sure that you have specified all the required preconditions and that the steps of the scenario are simple and clear.
Try to keep the tests as simple as possible. If there are multiple conditions or the steps are too long you must split the test to make shorter ones that test a single path of actions.
Always try to keep tests as independent as possible.
Understand the design
Please read the Automation design rationale and implementation.
QA team at Openbravo has created a framework to ease test automation process and to assure that tests will be simple, reusable, stable and coherent.
You should follow the same guidelines, this way you won't have to start the automation from zero; and it's going to be easier for you to execute the tests and review executions.
Read the documentation and implementation of the main classes
The source code of tests cases is publicly available at Openbravo's mercurial server.
You can get it or configure Eclipse to see how the common classes and existing tests have been coded.
Look for code that you can reuse
Chances are that some of the code you require was already written by somebody else. You should start looking for classes that you can reuse or extend.
Most of the interactions of a test should be done through the test controllers explained here. Chances are that we have already generated the test controller for the window you are generating, and then you would just have to write the test case..
Classes created for tests already automated are grouped on packages with the name of the corresponding menu section. For example, there's a package named com.openbravo.test.integration.testscripts.general.application and another called com.openbravo.test.integration.testscripts.procurement.transactions. If you are looking for a specific screen, check if there's a class for it in the package with the same name of it's parent menu item.
Code missing screen definitions
If the screen classes required for your test hasn't been created, you will have to create them and write the code to access HTML elements, execute and verify actions.
You should follow the same convention and store new classes on the package named after the menu item from which the screen is accessed.
If the screen classes already exist, but there are missing actions and verifications to complete your test, you should edit and extend those classes.
First, identify the HTML elements of the screen that you need to click, type to, select from or manipulate in some other way. Read the source of the page or use Firebug or Xpath extensions to find more information of the element. For each element, you should instantiate a base SmartClient UI test class as explained in the implementation section, using the object string of the element.
For example, in order to execute actions on the complete button of a tab, you would have to write something like this:
private static final String REGISTRY_KEY_BUTTON_COMPLETE = "org.openbravo.client.application.toolbar.button.documentAction.186" Button buttonComplete = new Button(TestRegistry.getObjectString(REGISTRY_KEY_BUTTON_COMPLETE));
Note: You must set test.environment=true in Openbravo.properties file to execute correctly automated tests. If is not set as true, you can find the following error message: 'test.environment' setting from Openbravo.properties file is not set as 'true'. Activate it to get tests working properly
Note: you might find some elements that are not implemented using SmartClient. In order to automate those screens, please refer to the documentation of the 2.50 version of the testing framework. |
After you have coded instantiated the right class for every UI element, read test documentation again to define the functions and parameters required to execute it. For example, if the test says that a purchase order header for a business partner has to be completed; you must define a function like the following:
/** * Process the order. * * @param action * The action to process. */ private void process(String action) { logger.debug(String.format("Process sales order header with action '%s'.", action)); buttonComplete.click(); RequestProcessPopUp popUp = new RequestProcessPopUp(REGISTRY_KEY_POP_UP_REQUEST_PROCESS); popUp.process(action); SeleniumSingleton.INSTANCE.switchTo().defaultContent(); waitUntilMessageVisible(); }
Finally, take from the documentation the things that you must verify to assure that the test passed or failed. To check a message, or to verify that a text field has the expected value are common verifications. This is the most important part of the test, and you must define additional functions with assertions for every verification.
Define the dependencies datasets
If there are preconditions for your test to be executed, or it requires some data before it can be run, the data should be inserted into the database using DbUnit. For this, precondition data has to be expressed as FlatXMLDataSet files that will be loaded into the database by DbUnit.
First define what data is required by the test. For example, in order to test that a Sales Order can be completed, there must be an existent opened Sales Order in the system.
Then, we recommend to follow all the steps in Openbravo ERP interface that are required to create that data. It is possible to define the dataset directly by hand but it requires a lot of knowledge of Openbravo ERP database model, it is hard and error prone.
Once that precondition data is present in database you will have to extract that data with a SQL query. For the example of the Sales Order, something like this will work:
select * from c_order where c_order_id = '{The ID of the last added order}';
After checking that the returned records are the ones required by your test, you can either export the rows as XML from your SQL client, or use the FlatXMLDataSets utility class.
Note: it is probable that your client doesn't export the XML on the format expected by DbUnit, so if you choose that option you will have to make sure that the XML file can be interpreted by DbUnit. We recommend to use the utility class, as the file exported can be directly used by DbUnit. |
Note: Some test will require more than one record, or records from more than one table. For example, a test that requires some Sales Order lines. We recommend to keep each dataset as small as possible and then composite them on a single dataset as explained later. A good idea would be to keep records only from one table on each dataset. |
At this moment you should have all the data as XML datasets. But this can't be directly inserted into the database because some values should be unique. On our example, if we try to add the Sales Order as was exported obviously it will fail because a record with the same ID already exists on database. To solve this we use placeholder objects that later will be replaced by UUIDs to assure that the same dataset can be inserted many times without problems. So, replace every value on your dataset that has to unique by something like [Placeholder].
Note: If the dataset is composed by multiple records related by foreign keys, the placeholder name should be the same to hold this relations. For example, on the case of a Sales Order and Sales Order Lines we set the value of c_order_id on the dataset to [C_ORDER_ID]. If we want this order to have some lines, on the field c_order_id of the lines we have to set the same placeholder: [C_ORDER_ID] |
An additional consideration has to be taken if we require to select the precondition data from a group of similar data. In these cases an additional placeholder that will be know by the test can be used as an identifier. For example, in order to complete the Sales Order it has to be selected on the grid view that shows all existing Sales Orders. If we define a placeholder for the document number (something like documentno=[DocumentNumber] on the XML dataset), then we will be able to locate our Sales Order from the rest and complete the correct one.
Now the XML files should be ready, so tehy can be handled by DbUnit. And we do this on the test controller.
Write the test controller and the test case
At this point, all requirements to run the test are coded and ready to be executed. The last classes that have to be created are the test controller and teh test case.
The test controller is optional, but as is explained in the implementation section, it improves readability and expressiveness of your tests. So its a good idea to write it.
In the test case class you will define every step of the test, calling the test controller (or directly the screen definitions if you didn't defined a controller) to execute the desired action and verify that it was correctly executed.
The name of this class must begin with the identifier of the test, followed by a short description of the process being tested. In addition, it must inherit from OpenbravoERPTest because it includes preconditions and global variables required for every test.
This class will have one and only one function annotated with junit's @Test tag; and this function will have a descriptive name of the things it's testing.
Example: from FINd_FinancialAccountAddTransaction
@Test public void transactionShouldBeAddedInFinancialAccount() throws IOException, OpenbravoERPTestException { logger.info("** Start of test case [FINd010] Create Purchase Invoice. **"); final PurchaseInvoice purchaseInvoice = new PurchaseInvoice(mainPage).open(); purchaseInvoice.create(purchaseInvoiceHeaderData); purchaseInvoice.assertSaved(); purchaseInvoice.assertData(purchaseInvoiceHeaderVerificationData); purchaseInvoice.edit(purchaseInvoiceHeaderEditionData); purchaseInvoice.assertSaved(); PurchaseInvoice.Lines purchaseInvoiceLines = purchaseInvoice.new Lines(mainPage); purchaseInvoiceLines.create(purchaseInvoiceLinesData); purchaseInvoiceLines.assertSaved(); purchaseInvoiceLines.assertData(purchaseInvoiceLinesVerificationData); purchaseInvoice.complete(); purchaseInvoice .assertProcessCompletedSuccessfullyContentMatch("Payment No\\. (.*) has been created");
If the test has some preconditions that will be inserted into database with DbUnit (as explained in previous section), some work has to be done before.
For this case, we should override the setup function and perform all DbUnit actions there.
@Override @Before public void setUp() throws Exception { // DbUnit actions here. super.setUp(); }
The first DbUnit action will be to get a connection to the database:
final Connection connection = DataAccess.connect(); final IDatabaseConnection dbUnitconnection = Connections.getDbUnitConnection(connection);
Then, if the dataset is split in various FlatXMLDataSet files, we will have to make a composite dataset out of them:
IDataSet compositeDataSet = CompositeDataSets.compositeFromFlatXmlDataSets(pathToDataset1, pathToDataset2);
After that, the placeholder objects should be replaced by the proper values that will be used on the test. Either UUIDs or a know value:
ReplacementDataSet replacementDataSet = new ReplacementDataSet(compositeDataSet); // Replace the column value that will be used to identify the order. replacementDataSet.addReplacementObject("[DocumentNumber]", documentNumber); // Replace the rest values with UUIDs. ReplacementDataSets.replaceWithUUIDs(replacementDataSet);
Finally, the REFRESH operation will be executed in order to insert the values into the Database:
try { DatabaseOperation.REFRESH.execute(dbUnitconnection, replacementDataSet); } finally { connection.close(); }
You can find more information at Test Case Walkthrough
Test your test
Execute your test as many times as possible under multiple and variable environments. After you are sure that it will work as expected, and that you didn't forget preconditions, steps or verifications, you can add it to a testing suite and include it to a phase of your testing process.