fineract-testing
Choose, write, run, and verify tests for Apache Fineract changes, from JUnit unit tests to Cucumber end-to-end scenarios. Get guidance on the right suite, required server setup, and how to interpret results so you can check that a change works.
OriginalShow the original description
Choose, write, run and verify tests for Apache Fineract changes, covering JUnit unit tests, the fineract-provider Cucumber tests, Feign-client integration tests, the two-factor and OAuth2 suites, and Cucumber E2E scenarios. Use when adding or changing tests, when a code change needs test coverage, when a test fails, or before claiming that a change works.
Run score Not tested
See how to installGood for
- Choosing a test suite for an Apache Fineract change
- Adding unit, integration, or Cucumber coverage
- Investigating a failing or flaky test
- Verifying test results before reporting a change as working
Files included (1)
- SKILL.md8.8 KB
SKILL.md (original)
Review the instructions the agent will receive before you install.
Fineract Testing
Paths are relative to the repository root, and .adoc names refer to
fineract-doc/src/docs/en/chapters/testing/. Each rule below comes from the file or
check named next to it; if this skill and that source disagree, the source wins.
Choose the suite
| Suite | Where the tests live | Needs a running server | Guide |
|---|---|---|---|
| Unit | src/test/java of the module you changed | No | CONTRIBUTING.md, "Unit tests" |
Cucumber in fineract-provider | fineract-provider/src/test/resources/features | No | .github/workflows/build-cucumber.yml |
| Integration | integration-tests | Yes | integration.adoc, integration-feign.adoc |
| Two-factor, OAuth2 | twofactor-tests, oauth2-tests | Yes, started in that auth mode | integration.adoc, "Authentication modes" |
| Cucumber E2E | fineract-e2e-tests-runner (features), fineract-e2e-tests-core (steps) | Yes | cucumber.adoc |
The build never starts a server. Start one before running any suite marked "Yes",
or every API call fails (CONTRIBUTING.md, "How to run tests").
Unit tests
- Use JUnit Jupiter, with Mockito through
@ExtendWith(MockitoExtension.class), as the example in rule 2 does. The modules exclude the JUnit 4 vintage engine (for examplefineract-provider/dependencies.gradle), so a JUnit 4@Testnever runs. - Code that reads the tenant or the business date needs the thread context. Set it in
@BeforeEachand clear it withThreadLocalContextUtil.reset()in@AfterEach.Moneyalso needs the tenant's rounding mode, which sits in a static cache thatreset()does not clear: set it withMoneyHelper.initializeTenantRoundingModeand remove it withMoneyHelper.clearCacheForTenant, asfineract-working-capital-loan/src/test/java/org/apache/fineract/portfolio/workingcapitalloan/service/WorkingCapitalLoanAsOfBalanceReadServiceImplTest.javadoes. - Let exceptions propagate instead of catching them. To test a failure, use
assertThrows, not@Test(expected = ...)(CONTRIBUTING.md, "Error Handling"). - Run one class with
./gradlew :<module>:test --tests <ClassName>. The command for the whole fast suite is inCONTRIBUTING.md, "Unit tests". If you changedfineract-provider, also run./gradlew :fineract-provider:cucumber, becausetestdoes not run its features.
Integration tests
New integration tests call the server through the generated Feign client. Read rules
IT-01 to IT-20 in integration-feign.adoc before writing one.
- Extend the base class for the product under test:
FeignLoanTestBase,FeignSavingsTestBase,FeignWorkingCapitalTestBaseorFeignDepositTestBaseinintegration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/, otherwiseFeignIntegrationTestone directory up. - The loan and savings bases register
LoanTestLifecycleExtensionandFeignSavingsLifecycleExtension. Before and after every test, these close, un-approve or reject every open loan or savings account in the tenant, so create accounts inside each test, not in@BeforeAll. - If your class needs its own
@BeforeAll, give it a new name. Reusing the base method's name (setupHelpers,setupSavingsHelpers,setupWorkingCapitalHelpers,setupDepositHelpers) hides it, and the base helpers are never set up. - Make calls through
FeignCalls(ok,executeVoid,fail,failVoid) fromfineract-client-feign/src/main/java/org/apache/fineract/client/feign/util/FeignCalls.java, and assert the exact status and error code of a failure (IT-02, IT-10). - Never import
io.restassured, and never add a file toconfig/checkstyle/restassured-baseline.xml: theFeignNoRestAssuredcheck inconfig/checkstyle/checkstyle.xmlfails the build. A test you migrate off REST Assured deletes its baseline entry in the same change (integration-feign.adoc, "The Baseline"). - If the generated model lacks a field, add it to the matching
*ApiResourceSwaggerclass and regenerate both clients. Do not work around it in the test (IT-05, "Fixing a Generated Model at Source"). - For anything that depends on the date, run the steps inside
runAt(date, ...). The loan, savings and working capital bases provide it; elsewhere, callrunAton aFeignBusinessDateHelper(integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/helpers/FeignBusinessDateHelper.java). It turns the business date on, sets it, and turns it off again afterwards. - Keep each test class self-contained, and undo any global configuration you change.
CI splits test classes across shards on each of PostgreSQL, MySQL and MariaDB
(
.github/workflows/build-postgresql.ymland its MySQL and MariaDB variants), so no class can rely on another one having run.
Keep the default lists in sync
Some tests compare the database with a list kept by hand. When your change adds one of these, update the list in the same change:
| When you add | Also update | Otherwise this fails |
|---|---|---|
A global configuration (c_configuration row) | GlobalConfigurationHelper.getAllDefaultGlobalConfigurations() in integration-tests/src/test/java/org/apache/fineract/integrationtests/common/GlobalConfigurationHelper.java | Tests that reset global configurations, such as GlobalConfigurationTest |
A scheduler job (JobName value) | Its job row, inserted by a Liquibase changeset | SchedulerJobsTest, which compares the two counts |
| An external business event type | ExternalEventConfigurationTestData in integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/modules/ | ExternalEventConfigurationIntegrationTest |
Cucumber E2E scenarios
- Put scenarios in a
.featurefile underfineract-e2e-tests-runner/src/test/resources/featuresand step definitions underfineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef(cucumber.adoc, "Writing New E2E Tests"). - On a fresh database, run once with
INITIALIZATION_ENABLED=trueto create the products and charges the scenarios expect, and enable the business date (cucumber.adoc, "Test Data Initialization" and "Business Date Configuration"). - From
fineract-e2e-tests-runner, run one feature with../gradlew cucumber -Pcucumber.features="src/test/resources/features/<Name>.feature", and filter with-Pcucumber.tags. A filter that matches nothing reports0 scenariosand still exits 0, so read the summary line (integration.adoc, "The WAR deployment"). - Event assertions are skipped unless
EVENT_VERIFICATION_ENABLED=true. E2E CI sets it and runs ActiveMQ (.github/workflows/build-e2e-tests.yml,docker-compose-postgresql-test-activemq.yml), so a local run without it does not check events. - Use
@TestRailId:C<number>only for an existing TestRail case, because results are posted to that case (fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/testrail/TestRailClient.java). If there is none, ask in the PR rather than guessing.
Run and verify
- Start a server first. For the integration suites, use the Docker stack in
CONTRIBUTING.md, "Integration tests", which CI also uses; that section also covers running without Docker. For E2E, see the previous section. - Run the tests you added or changed against that server. Compiling and
spotlessCheckare not verification (IT-18). - If a test fails, run it at the base commit before blaming your change (IT-20). If your change touches server code, rebuild and restart the server at the base commit too.
- Check the report for skipped tests. Some
fineract-providertests are skipped, not failed, when Docker is not running (@Testcontainers(disabledWithoutDocker = true)). - If Gradle reports the test task as
UP-TO-DATEorFROM-CACHE, the tests did not run. Add--rerun-tasks(CONTRIBUTING.md, "How to run tests"). - Before pushing, run
./gradlew spotlessApplyand the checks in.github/workflows/build-quality-checks.ymlthat your change touches (Checkstyle, Spotless, SpotBugs, RAT, Javadoc).
Flaky tests
Follow CONTRIBUTING.md, "Pull Requests". First rule out your own change ("Run and
verify", step 3). Search JIRA for the test; if there is no report, file one and link it
to FINERACT-850. Propose @Disabled // TODO FINERACT-NNNN only when comments show the
test failing in at least 3 past PRs, and only in a separate PR.
Reviews
No reviews yet. Tell others what you thought.
Comments
No login needed. Share how it worked for you, ask a question, or note where it did not run.
No comments yet. Be the first to write one.