This topic provides advice and best practices for writing your own automated Selenium tests against LabKey Server.
Add Tests to a Module
Your module must be compatible with our standard gradle build (e.g. deploys locally by running './gradlew deployApp'). If it is, our gradle plugin will recognize any java code in the module's 'test/src' directory and make it available to our test runner. By default, it only searches in the 'org.labkey.test' package for actual test classes to run, though other classes will be available to your test code. If you have tests in a package named more appropriately for your organization, you can include them by specifying the 'extra.test.packages' property when running tests. See the related topics below for more information on running tests and defining test properties.
Helper Classes and Methods
Most helper classes live in the org.labkey.test.util package.
- Creating/Deleting containers
- Creating/Deleting users
- Defining groups and assigning permissions
The base test classes also expose a lot of basic LabKey functionality. If there is some core LabKey operation that you want to perform, there is probably a helper for it somewhere.
Test Flow
Current Selenium tests can't be considered to be "unit tests" but we use JUnit4 to control the execution and flow of tests. Each test class defines some setup steps, test cases, and cleanup steps.
These are done primarily via JUnit annotations.
- @BeforeClass
- The primary setup method for a test class. It is run once, before all test cases.
- This annotation only works on static methods so we have to jump through some hoops to actually utilize all of our non-static helpers.
- @Before
- Run once before each test. Not generally necessary but can be used to do quick cleanup between test cases.
- @Test
- Each test method should be independent and shouldn't interfere with other tests. Different tests might modify the test environment (e.g. adding or modifying imported data) but it is your responsibility to make sure they don't step on each others' toes.
- Each test method might check several things but these should be reasonably small.
- @After/@AfterClass
- Do not use these. They interfere with our post-test cleanup and failure handling. Cleanup should be performed in a test's 'doCleanup' method.
- For similar reasons, you should avoid doing cleanup steps in a catch block.
- BaseWebDriverTest.doCleanup()
- Override this method to provide custom cleanup steps. Our test harness will run this before anything else in the test class and once at the end, if the test passes; it skips the cleanup for failed tests so that you can investigate further.
Class Patterns
Test Classes
- Selenium tests extend BaseWebDriverTest (BWDT). This will handle universal test steps such as launching the browser, logging in, and collecting screenshots for failed tests.
- The classes that BWDT extends (LabKeySiteWrapper and WebDriverWrapper) provide lots of basic functionality.
- LabKey specific functionality such as signing in, impersonation, setting passwords, and navigating to different projects or modules.
- General functionality such as inspecting the content of a page, setting form inputs, downloading files, and waiting for page loads.
- Should avoid directly interacting with the WebDriver or individual elements on the page, preferring instead to utilize helper, page, and component classes.
- Note: This is not a strict requirement. Our helper/page/component coverage is far from complete and sometimes you just need to click a button.
- Example: org.labkey.test.tests.issues.IssuesTest
Helper Classes
- These perform high level tasks that span numerous steps, such as creating users or importing data. They may use either the UI or the Java remote API, usually indicated by the class name.
- Example: org.labkey.test.util.APIContainerHelper
Utility Classes
- Collections of generally useful, usually static, utility methods.
- Example: org.labkey.test.WebTestHelper
- Note: The class name for these often include the word "Helper", which is a bit misleading.
Page Classes
- These encapsulate the functionality of a single page, usually corresponding to a LabKey action.
- Should act as at test API for the page, exposing methods to perform simple actions on the page and providing setters and getters for form elements.
- Non-getter methods should return the same page to allow method chaining.
- Methods that navigate should return an instance of a page class corresponding with the target page, if available.
- Example: org.labkey.test.pages.list.ImportListArchivePage
Component Classes
- These encapsulate a smaller component on the page. Ranging from something as simple as a combo box to something as complex as a data region.
- Conceptually similar to page classes just with a different scope.
- Example: org.labkey.test.components.ext4.Window
Test Templates
We have templates that create stub classes for tests, pages, or components. To use these templates you will need to
enable 'Project' templates in IntelliJ. Once enabled, they will be available in the type dropdown when you create a new Java file through IntelliJ.
Related Topics