[ 
https://issues.apache.org/jira/browse/FINERACT-2609?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Krishna Mewara updated FINERACT-2609:
-------------------------------------
    Description: 
h2. What this is

Moving Fineract's integration tests off raw RestAssured HTTP and onto the 
generated Feign
client ({{{}fineract-client-feign{}}}). I'm doing this Strangler Fig style: the 
new Feign helpers
sit alongside the existing RestAssured ones and tests move over in batches, so 
nothing breaks
in one go.

The reason is simple. RestAssured tests build JSON by hand, so a broken API 
contract only
shows up when CI runs. Feign is generated from the OpenAPI spec, so the same 
mistake won't
compile.

This is the umbrella issue. To close: FINERACT-2454
h2. When I'll call this done

All five of these:
 # No {{io.restassured}} or {{Utils.performServer*}} left in any test outside 
{{common/}}
 # {{BaseLoanIntegrationTest}} and {{BaseSavingsIntegrationTest}} are deleted
 # The RestAssured-only helpers in {{common/}} are gone or reduced to thin 
Feign wrappers
 # The build fails if someone adds a new {{io.restassured}} import
 # {{Utils.java}} keeps only the non-HTTP bits 
({{{}uniqueRandomStringGenerator{}}}, the login helper)

Number of helpers written isn't the finish line. Number of tests actually moved 
is.
h2. Scope note

The 50 Retrofit-based tests are out of scope here. They're already type-safe, 
so they're well
behind the 148 RestAssured ones in priority. {{IntegrationTest}} stays until 
someone picks them
up in a follow-up.
h2. Where I started — 2026-05-28

Frozen so we can see the distance travelled. I won't edit this table again.
||Metric||Count||
|Helper files in {{common/}}|123|
|Helpers using RestAssured only|53|
|Helpers using both RestAssured and Retrofit|18|
|Helpers already on Retrofit ({{{}Calls.ok{}}})|35|
|Helpers with no RestAssured (pure utility)|51|
|Test files (excluding {{common/}} and Feign)|312|
|Test files importing RestAssured|197 of 312 (63%)|
|Feign test files|10|
|Feign helpers|17|
|Feign modules|7|
|Wrapper interfaces|4|
h2. Where it stands now — 2026-07-31
||Metric||Start||Now||Left||
|Tests on Feign|10|*135* (869 test methods)|—|
|Tests on RestAssured|197|*148* (1,050 methods, ~82k lines)|148|
|Tests on Retrofit (neither RA nor Feign)|—|*50*|out of scope|
|Total test classes|312|333|—|
|Feign helpers|17|*30*|—|
|Feign modules|7|*12*|—|
|{{common/}} helpers still on RestAssured|53|*52*|52|
|{{Utils.java}} methods marked {{@Deprecated}}|0|*24 of 64*|—|

49 test files have come off RestAssured so far. The helper layer is more or 
less built at this
point; the bulk of what's left is moving the test files themselves.

If anyone wants to check these numbers, this is how I count them:
{code:bash}
cd integration-tests/src/test/java/org/apache/fineract/integrationtests
RA='io\.restassured|RequestSpecification|Utils\.performServer'
FG='client\.feign|Feign[A-Z][A-Za-z]*Helper|FeignLoanTestBase|FeignIntegrationTest'

grep -rl "@Test" . --include=*.java | wc -l                                     
# total
grep -rl "@Test" . --include=*.java | xargs grep -lE "$RA" | wc -l              
# on RestAssured
grep -rl "@Test" . --include=*.java | xargs grep -LE "$RA" | xargs grep -lE 
"$FG" | wc -l   # on Feign
grep -rl "@Test" . --include=*.java | xargs grep -LE "$RA" | xargs grep -LE 
"$FG" | wc -l   # on Retrofit
grep -rlE "$RA" ./common --include=*.java | wc -l                               
# RA helpers
{code}
h2. What's left, by area
||Area||Classes||Tests||Blocked on||
|Loan|57|470|nothing|
|Savings and deposits|19|199|deposit helpers not written yet|
|Organisation and misc|37|181|nothing|
|Jobs and batch|5|69|nothing|
|Client|9|55|nothing|
|Accounting|11|40|nothing|
|Datatable and entity|4|22|nothing|
|Reporting, shares, bulkimport, group|10|36|nothing|
|*Total*|*148*|*1,050*| |

These six are big enough that each one needs its own PR:
||Class||Tests||Lines||
|{{AdvancedPaymentAllocationLoanRepaymentScheduleTest}}|86|6,625|
|{{ClientLoanIntegrationTest}}|66|8,354|
|{{FixedDepositTest}}|47|3,200|
|{{ClientSavingsIntegrationTest}}|45|3,662|
|{{BatchApiTest}}|40|2,750|
|{{RecurringDepositTest}}|38|3,128|
h2. Old classes on the way out
||Class||Start||Now||Blocked on||
|{{BaseLoanIntegrationTest}}|121|*53* (52 subclasses)|nothing|
|{{BaseSavingsIntegrationTest}}|—|*3 subclasses*|savings batch|
|{{ClientHelper}}|216|*170*|client batch|
|{{LoanTransactionHelper}}|118|*125*|loan batch|
|{{SavingsAccountHelper}}|37|*35*|savings batch|
|{{Utils.java}}|309|*345*|everything else|
|RestAssured-only helpers in {{common/}}|53|*52*|per-area Feign helpers|

Worth flagging: {{Utils.java}} and {{LoanTransactionHelper}} both went 
{*}up{*}, not down. New tests are still being written against the old layer 
while I'm migrating the old ones off it.
That's what exit criterion #4 is for.
h2. Things I know are still open

A few gaps I'd record:
 * {{FeignLoanHelper}} still has a handful of methods that take a JSON string 
and post it
through the old RestAssured utility. Any test going down those paths isn't 
genuinely off
RestAssured, so the 135 figure above is slightly generous. Separate ticket for 
it.
 * One test living under the Feign folder still builds a RestAssured request 
spec itself.
 * {{FeignLoanTestBase}} is now 1,562 lines, 224 methods and 99 subclasses. 
It's drifting
towards being the same kind of god class I'm trying to delete. I'd rather split 
it once the
area batches have landed than churn it mid-migration.

h2. How the Feign side is put together

Helpers live under {{client/feign/helpers/}} (30 of them so far). Each takes 
{{FineractFeignClient}} in the constructor, calls the API through {{ok(...)}} / 
{{{}fail(...) }}from \{{{}FeignCalls{}}}, and returns the whole response object 
rather than just an ID.

Request building lives in {{client/feign/modules/}} (12 files: the 
{{{}*RequestBuilders{}}}, {{{}LoanProductTemplates{}}}, 
{{{}LoanTestValidators{}}}, test data holders). Tests extend 
{{{}FeignIntegrationTest{}}}, {{FeignLoanTestBase}} or 
{{{}FeignSavingsTestBase{}}}.

Both clients are on the classpath at the same time. The {{exclude}} in 
\{{dependencies.gradle }}keeps the duplicate model classes apart.

Conventions I've settled on as I've gone:
 * Feign helpers are new classes, not extra methods bolted onto the old helpers
 * Wrapper interfaces only where the generated name is unreadable 
({{{}create6(){}}} → {{{}createClient(){}}})
 * New shared code goes in a helper or a module, never on the test base. 
One-off methods stay {{private}} in the test that needs them.
 * Where the generated model genuinely can't express a call, I drop to a small 
raw-HTTP helper and leave a comment explaining why. Never RestAssured. If the 
gap is only a field or two, I fix the Swagger DTO and regenerate instead. I 
keep a running list of every one of these so none of them get forgotten.
 * Coexistence was the right call for the first phase. It ends when criterion 
#4 lands.

h2. PR roadmap

I'm keeping the PR count deliberately low and putting the detail into commits 
instead. Each
remaining PR is one area, broken into commits that each build and pass on their 
own, so they
can be reviewed one at a time without the PR itself becoming unreviewable.
||PR||What||Files||Tests||Ticket||GitHub||Status||
|1|Savings helper, test base, Swagger fields|—|—|FINERACT-2620, 2626|#5907, 
#5934|Merged|
|2|Client helper build-out, Swagger fields|—|—|FINERACT-2631, 2632|#5954, 
#5955|Merged|
|3|Charges and delinquency helpers|—|—|FINERACT-2635|#5978|Merged|
|4|Loan helper: charges, transitions, 
disbursement|—|—|FINERACT-2640|#5997|Merged|
|5|Loan tests, 4 tiers|—|—|FINERACT-2649|4 PRs, see ticket|Last tier in review|
|6|Group and centre|3|16|FINERACT-2718|#6194|*In review — I'm here*|
|7|Loan: money movement|21|360|to raise|—|Next|
|8|Loan: lifecycle, product, COB|33|113|to raise|—|Not started|
|9|Savings and deposits|20|209|to raise|—|Not started|
|10|Client, charges, accounting|20|101|to raise|—|Not started|
|11|Organisation, jobs, batch, config|33|228|to raise|—|Not started|
|12|Closeout|—|—|to raise|—|Not started|
|S1|Bulk import, shares, reporting, smoke tests|21|39|stretch|—|Not started|
|S2|Split {{FeignLoanTestBase}}|—|—|stretch|—|Not started|
|S3|The 50 Retrofit tests|50|—|stretch|—|Not started|

PRs 7 to 11 add up to 127 files and 1,011 tests. S1 covers the last 21 files 
and 39 tests.
h2. Log

One line per merge. I don't edit old entries, only add to the bottom.
||Date||PR||Ticket||What went in||
|2026-06-04|[#5934|https://github.com/apache/fineract/pull/5934]|FINERACT-2626|Added
 {{rejectedOnDate}} and {{withdrawnOnDate}} to the savings Swagger spec. The 
generated model was missing them, so a reject call silently did nothing. Needed 
before #5907 could land.|
|2026-06-07|[#5907|https://github.com/apache/fineract/pull/5907]|FINERACT-2620|First
 area done end to end. 10 new files: savings helper, test base, lifecycle 
extension, request builders, and an 8-test lifecycle test to prove the pattern 
works.|
|2026-06-09|[#5955|https://github.com/apache/fineract/pull/5955]|FINERACT-2632|Client
 Swagger fields the server accepts but the model didn't have: 
{{{}submittedOnDate{}}}, the withdrawal fields, and 
{{{}firstname{}}}/{{{}lastname{}}} on PUT.|
|2026-06-09|[#5954|https://github.com/apache/fineract/pull/5954]|FINERACT-2631|{{FeignClientHelper}}
 from 4 methods to 16, plus {{ClientRequestBuilders}} and a full client 
lifecycle test.|
|2026-06-11|[#5978|https://github.com/apache/fineract/pull/5978]|FINERACT-2635|Charges
 and delinquency: {{FeignChargesHelper}} (14 methods), 
{{{}ChargeRequestBuilders{}}}, and a 7-test delinquency lifecycle. Also fixed 4 
fields missing from {{PostChargesRequest}} that were sending nulls on PUT.|
|2026-06-21|[#5997|https://github.com/apache/fineract/pull/5997]|FINERACT-2640|Loan
 helper grew charge management, state transitions, disbursement details and 
reschedule: 11 charge methods, 6 transitions, 4 disbursement methods.|
|from 2026-06-26|4 PRs|FINERACT-2649|The loan test migration, done in four 
tiers. Tier 4 is the big one at 92 files. Per-PR detail and review notes are on 
that ticket rather than duplicated here. Final tier is in review.|
|2026-07-28|[#6194|https://github.com/apache/fineract/pull/6194]|FINERACT-2718|Group
 and centre. New helpers for group, centre, staff and GLIM. Migrated 
{{{}CenterIntegrationTest{}}}, {{GroupTest}} and {{GroupLoanIntegrationTest}} 
(16 tests) and retired a raw-HTTP stopgap helper that was Feign in name only. 
No changes to the shared loan test base. In review.|

  was:
h2. Overview

Migrate Fineract's integration test infrastructure from raw RestAssured HTTP 
calls to the
type-safe Feign client ({{{}fineract-client-feign{}}}). Following the Strangler 
Fig pattern —
new Feign helpers coexist alongside legacy RestAssured helpers, tests migrated 
incrementally.
No big bang rewrite.

To close: FINERACT-2454
h2. Why migrate?
 * RestAssured tests use raw JSON strings and untyped HTTP — brittle, no 
compile-time safety
 * Feign client is type-safe, auto-generated from the OpenAPI spec
 * Catch API contract drift at compile time, not at runtime in CI

h2. Current State
||Metric||Count||
|Total helper files in {{common/}}|123|
|Helpers with RestAssured only (unmigrated)|53|
|Helpers with both RestAssured + Retrofit (mixed)|18|
|Helpers already using Retrofit ({{{}Calls.ok{}}})|35|
|Helpers with NO RestAssured (pure utility)|51|
|Total test files (excluding {{common/}} and Feign)|312|
|Test files directly importing RestAssured|197 of 312 (63%)|
|Existing Feign test files|10|
|Existing Feign helpers|17|
|Existing Feign modules|7|
|Existing wrapper interfaces|4|
h2. Existing Feign Infrastructure

These are already merged and in {{{}upstream/develop{}}}. Listed here so the 
scope of remaining
work is clear and we don't accidentally duplicate what already exists.
h3. Base Classes
||Class||Role||Replaces||
|{{FeignIntegrationTest}}|Root base for all Feign tests|{{IntegrationTest}} 
(Retrofit-based)|
|{{FeignLoanTestBase}}|Wires all loan helpers, ready for loan test 
migration|{{BaseLoanIntegrationTest}} (decommission target)|
h3. Helpers (under {{{}client/feign/helpers/{}}})
||Helper||Replaces||Coverage||
|{{FeignLoanHelper}}|{{LoanTransactionHelper}} (3,250 lines)|~16% — core 
lifecycle only|
|{{FeignTransactionHelper}}|Extracted from {{LoanTransactionHelper}}|repayment, 
chargeOff, reAge, inline COB|
|{{FeignClientHelper}}|{{ClientHelper}} (1,207 lines)|~6 of ~50 methods|
|{{FeignAccountHelper}}|{{AccountHelper}}|GL account lookup|
|{{FeignBusinessDateHelper}}|{{BusinessDateHelper}}|Full functional replacement|
|{{FeignJournalEntryHelper}}|{{JournalEntryHelper}}|Journal verification|
|{{FeignOfficeHelper}}|{{OfficeHelper}}|Full functional replacement|
|{{FeignSchedulerHelper}}|{{SchedulerJobHelper}}|Full functional replacement|
|{{FeignGlobalConfigurationHelper}}|{{GlobalConfigurationHelper}}|Full 
functional replacement|
|{{FeignWorkingCapitalLoanHelper}}|{{WorkingCapitalLoanHelper}}|WC loan ops|
|{{{}FeignSearchHelper{}}}, {{{}FeignTaxComponentHelper{}}}, 
{{FeignTaxGroupHelper}}|No legacy equivalent|New capability|
|{{{}FeignNotificationHelper{}}}, {{{}FeignLoanOriginatorHelper{}}}, 
{{FeignExternalEventHelper}}|No legacy equivalent|New capability|
h2. Migration Tiers
h3. Tier 1 — High-Impact
||Helper||Importers||RestAssured %||Feign existence||
|{{Utils.java}}|309|100%|None — migrate last|
|{{ClientHelper.java}}|216|~80%|{{FeignClientHelper}} (6 methods — extend in PR 
2)|
|{{BaseLoanIntegrationTest.java}}|121|~95%|{{FeignLoanTestBase}} — exists, 
decommission after charge coverage added|
|{{LoanTransactionHelper.java}}|118|~55%|{{FeignLoanHelper}} + 
{{FeignTransactionHelper}} — extend in PR 4|
|{{SavingsAccountHelper.java}}|37|~97%|None — greenfield target for PR 1|
h3. Tier 2 — Medium-Impact
||Helper||Importers||Feign Beachhead||
|{{BusinessDateHelper}}|61|{{FeignBusinessDateHelper}} (done)|
|{{AccountHelper}}|60|{{FeignAccountHelper}} (done)|
|{{ChargesHelper}}|55|None — PR 3|
|{{DelinquencyBucketsHelper}}|36|None — PR 3|
|{{SchedulerJobHelper}}|35|{{FeignSchedulerHelper}} (done)|
|{{GlobalConfigurationHelper}}|26|{{FeignGlobalConfigurationHelper}} (done)|
|{{JournalEntryHelper}}|24|{{FeignJournalEntryHelper}} (done)|
|{{OfficeHelper}}|19|{{FeignOfficeHelper}} (done)|
|{{GroupHelper}}|17|None — PR 5|
h3. Tier 3 — Low-Impact / Niche

{{BatchHelper}} (7 importers), {{{}FixedDepositAccountHelper{}}}, 
{{{}RecurringDepositAccountHelper{}}},
and domain-specific helpers with <10 importers each.
h3. Foundation Layer

{{Utils.java}} (309 importers) is the RestAssured gateway that nearly all 
helpers delegate to.
{*}Deprecate last{*}, only after all helpers above are migrated. The 
RA-specific methods
({{{}initializeRESTAssured(){}}}, HTTP request wrappers) can be {{@Deprecated}} 
progressively —
but {{uniqueRandomStringGenerator()}} and 
{{loginIntoServerAndGetBase64EncodedAuthenticationKey()}}
are used widely even in non-RA code, so those stay until their callers are 
migrated.
h2. Architecture Pattern

New {{FeignXxxHelper}} classes live under {{{}client/feign/helpers/{}}}. They:
 * Take {{FineractFeignClient}} via constructor injection
 * Use {{ok(() -> ...)}} for API calls (via {{FeignCalls}} utility)
 * Tests extend {{FeignIntegrationTest}} base class
 * Share the same model classes ({{{}org.apache.fineract.client.models.*{}}}) 
as Retrofit

Legacy and Feign helpers coexist — both {{fineract-client}} (Retrofit) and
{{fineract-client-feign}} are on the classpath simultaneously. The {{exclude}} 
in
{{dependencies.gradle}} prevents duplicate model classes.
h2. Key Design Decisions
 # *Separate Feign helper classes* — not dual methods in existing helpers
 # Both clients share model classes — no conflicts
 # Thin wrapper interfaces only for APIs with unreadable generated names (e.g. 
{{create6()}} → {{{}createClient(){}}})
 # Coexistence over replacement — 197 test files still use RestAssured, helper 
migration enables but doesn't force test-level migration

h2. Decommission Plan

These classes will be retired once their Feign replacement has full method 
coverage.
Both old and new coexist until importer counts reach zero.
||Class||Importers||Depends On||
|{{BaseLoanIntegrationTest}}|121|PR 4 (charge management added to 
{{{}FeignLoanHelper{}}})|
|{{BaseSavingsIntegrationTest}}|—|PR 1 ({{{}FeignSavingsHelper{}}} + 
{{{}FeignSavingsTestBase{}}})|
h2. PR Roadmap
h3. Core PRs
||PR||Scope||Status||
|PR 1|{{FeignSavingsHelper}} + {{FeignSavingsTestBase}} + first savings 
test|Done|
|PR 2|Extend {{FeignClientHelper}} (update, delete, search, status 
transitions)|Done|
|PR 3|{{FeignChargesHelper}} + {{FeignDelinquencyHelper}}|Done|
|PR 4|Extend {{FeignLoanHelper}} — charge management + remaining disbursal 
methods|Done|
|PR 5|{{FeignGroupHelper}} + {{FeignCenterHelper}}|Not Started|
|PR 6|Migrate 5–10 simple test files end-to-end from RestAssured to Feign|Not 
Started|
h3. Stretch PRs
||PR||Scope||Status||
|PR S1|Batch migrate {{BaseLoanIntegrationTest}} importers to 
{{FeignLoanTestBase}} (after PR 4)|In Review|
|PR S2|{{FeignFixedDepositHelper}} + {{FeignRecurringDepositHelper}}|Not 
Started|
|PR S3|{{@Deprecated}} on RestAssured-specific methods in {{Utils.java}}|Not 
Started|
h2. Progress Log
||Date||PR||Ticket||Notes||
|2026-06-04|[#5934|https://github.com/apache/fineract/pull/5934]|FINERACT-2626|Added
 missing `rejectedOnDate` and `withdrawnOnDate` fields to 
`PostSavingsAccountsAccountIdRequest` in Savings Swagger spec. Prerequisite for 
#5907 the generated Feign client model was missing these fields, causing the 
reject command to silently fail.|
|2026-06-07|[#5907|https://github.com/apache/fineract/pull/5907]|FINERACT-2620|Type-safe
 Feign-based helpers and integration tests for Savings domain. 10 new files: 
`FeignSavingsHelper`, `FeignSavingsProductHelper`, 
`FeignSavingsTransactionHelper`, `FeignSavingsTestBase`, 
`FeignSavingsLifecycleExtension`, `SavingsRequestBuilders`, `SavingsTestData`, 
`FeignTestConstants`, and `FeignSavingsLifecycleTest` (8 tests). Helpers return 
full response objects for reusability. Depends on #5934 for correct 
`rejectedOnDate` support.|
|2026-06-09|[#5955|https://github.com/apache/fineract/pull/5955]|FINERACT-2632|Added
 missing fields to `PostClientsRequest` (submittedOnDate), 
`PostClientsClientIdRequest` (withdrawalDate, withdrawalReasonId, 
reopenedDate), and `PutClientsClientIdRequest` (firstname, lastname) so the 
generated Feign client models match what the server actually accepts. 
Prerequisite for #5954.|
|2026-06-09|[#5954|https://github.com/apache/fineract/pull/5954]|FINERACT-2631|Extends
 FeignClientHelper from 4 to 16 methods. Adds `ClientRequestBuilders` and 
`FeignClientLifecycleTest` covering the full client lifecycle: pending 
creation, activate, close, reject, reactivate, withdraw, undo-reject, 
undo-withdraw, update, delete, search, and account retrieval. Depends on #5955.|
|2026-06-11|[#5978|https://github.com/apache/fineract/pull/5978]|FINERACT-2635|Extends
 the Feign migration to the Charges and Delinquency domains. New files: 
`ChargeRequestBuilders` (static typed factories mirroring 
`ClientRequestBuilders`), `FeignChargesHelper` (14 methods across `ChargesApi` 
and `ClientChargesApi`), `FeignDelinquencyLifecycleTest` (7 ordered E2E tests 
via native `DelinquencyBucketsHelper`/`DelinquencyRangesHelper`). Fixed Swagger 
spec gap in `ChargesApiResourceSwagger` — 4 fields missing from 
`PostChargesRequest` caused silent null sends on PUT. Refactored 3 
enricher/report tests to use `chargesHelper.createLoanDisbursementCharge()`. 
`LoanChargesApi` and loan delinquency actions deferred to PR 4.|
|2026-06-21|[#5997|https://github.com/apache/fineract/pull/5997]|FINERACT-2640|Extends
 `FeignLoanHelper` with loan charge management, state transitions, disbursement 
details, and reschedule methods (PR 4 of the roadmap). 3 files, +284 −9. Added 
11 loan charge lifecycle methods (`addLoanCharge`, `getLoanCharges`, 
`updateLoanCharge`, `deleteLoanCharge`, `waiveLoanCharge`, `payLoanCharge`, 
`adjustLoanCharge`, etc.), 6 state-transition methods (`closeLoan`, 
`closeAsRescheduled`, `forecloseLoan`, `assignLoanOfficer`, 
`unassignLoanOfficer`, `recoverGuarantee`), disbursement detail methods 
(`addAndDeleteDisbursementDetail`, `getDisbursementDetail`, 
`updateDisbursementDate`, `modifyAvailableDisbursementAmount`), and reschedule 
methods via `RescheduleLoansApi`. Extended `LoanRequestBuilders` with static 
typed factories for all new operations. Updated `FeignLoanTestBase` with 
delegate methods.|
|2026-06-26|[#6005|https://github.com/apache/fineract/pull/6005]|FINERACT-2649|Migrates
 5 Tier 1 loan integration tests from `BaseLoanIntegrationTest` (REST-assured) 
to `FeignLoanTestBase` (Feign client). 15 files, +927 −229. Migrated tests: 
`LoanPrepayAmountTest`, `LoanProductWithChargeOffBehaviourTest`, 
`LoanInterestRateFrequencyTest`, `LoanDueCalculationTest`, 
`FixedLengthLoanProductIntegrationTest`. Infrastructure additions: 
`FeignRawHttpHelper` for raw JSON when explicit nulls are needed, 
`LoanProductTemplates` (3 templates), `LoanTestValidators` 
(`verifyRepaymentSchedule`, `verifyTransactions`). Extended `FeignLoanTestBase` 
with builders, installment/transaction wrappers, and utilities from 
`BaseLoanIntegrationTest`. Bug fixes: `FeignClientHelper.createClient()` uses 
fixed past activation date matching `ClientHelper.DEFAULT_DATE`; 
`FeignBusinessDateHelper` date-format overloads; automatic ISO vs 
human-readable date detection in `runAt()`/`updateBusinessDate()`.|


> Migrate integration test helpers from RestAssured to Feign client
> -----------------------------------------------------------------
>
>                 Key: FINERACT-2609
>                 URL: https://issues.apache.org/jira/browse/FINERACT-2609
>             Project: Apache Fineract
>          Issue Type: Improvement
>            Reporter: Krishna Mewara
>            Assignee: Krishna Mewara
>            Priority: Trivial
>              Labels: beginner, beginner-friendly, feign-migration, 
> test-infrastructure
>
> h2. What this is
> Moving Fineract's integration tests off raw RestAssured HTTP and onto the 
> generated Feign
> client ({{{}fineract-client-feign{}}}). I'm doing this Strangler Fig style: 
> the new Feign helpers
> sit alongside the existing RestAssured ones and tests move over in batches, 
> so nothing breaks
> in one go.
> The reason is simple. RestAssured tests build JSON by hand, so a broken API 
> contract only
> shows up when CI runs. Feign is generated from the OpenAPI spec, so the same 
> mistake won't
> compile.
> This is the umbrella issue. To close: FINERACT-2454
> h2. When I'll call this done
> All five of these:
>  # No {{io.restassured}} or {{Utils.performServer*}} left in any test outside 
> {{common/}}
>  # {{BaseLoanIntegrationTest}} and {{BaseSavingsIntegrationTest}} are deleted
>  # The RestAssured-only helpers in {{common/}} are gone or reduced to thin 
> Feign wrappers
>  # The build fails if someone adds a new {{io.restassured}} import
>  # {{Utils.java}} keeps only the non-HTTP bits 
> ({{{}uniqueRandomStringGenerator{}}}, the login helper)
> Number of helpers written isn't the finish line. Number of tests actually 
> moved is.
> h2. Scope note
> The 50 Retrofit-based tests are out of scope here. They're already type-safe, 
> so they're well
> behind the 148 RestAssured ones in priority. {{IntegrationTest}} stays until 
> someone picks them
> up in a follow-up.
> h2. Where I started — 2026-05-28
> Frozen so we can see the distance travelled. I won't edit this table again.
> ||Metric||Count||
> |Helper files in {{common/}}|123|
> |Helpers using RestAssured only|53|
> |Helpers using both RestAssured and Retrofit|18|
> |Helpers already on Retrofit ({{{}Calls.ok{}}})|35|
> |Helpers with no RestAssured (pure utility)|51|
> |Test files (excluding {{common/}} and Feign)|312|
> |Test files importing RestAssured|197 of 312 (63%)|
> |Feign test files|10|
> |Feign helpers|17|
> |Feign modules|7|
> |Wrapper interfaces|4|
> h2. Where it stands now — 2026-07-31
> ||Metric||Start||Now||Left||
> |Tests on Feign|10|*135* (869 test methods)|—|
> |Tests on RestAssured|197|*148* (1,050 methods, ~82k lines)|148|
> |Tests on Retrofit (neither RA nor Feign)|—|*50*|out of scope|
> |Total test classes|312|333|—|
> |Feign helpers|17|*30*|—|
> |Feign modules|7|*12*|—|
> |{{common/}} helpers still on RestAssured|53|*52*|52|
> |{{Utils.java}} methods marked {{@Deprecated}}|0|*24 of 64*|—|
> 49 test files have come off RestAssured so far. The helper layer is more or 
> less built at this
> point; the bulk of what's left is moving the test files themselves.
> If anyone wants to check these numbers, this is how I count them:
> {code:bash}
> cd integration-tests/src/test/java/org/apache/fineract/integrationtests
> RA='io\.restassured|RequestSpecification|Utils\.performServer'
> FG='client\.feign|Feign[A-Z][A-Za-z]*Helper|FeignLoanTestBase|FeignIntegrationTest'
> grep -rl "@Test" . --include=*.java | wc -l                                   
>   # total
> grep -rl "@Test" . --include=*.java | xargs grep -lE "$RA" | wc -l            
>   # on RestAssured
> grep -rl "@Test" . --include=*.java | xargs grep -LE "$RA" | xargs grep -lE 
> "$FG" | wc -l   # on Feign
> grep -rl "@Test" . --include=*.java | xargs grep -LE "$RA" | xargs grep -LE 
> "$FG" | wc -l   # on Retrofit
> grep -rlE "$RA" ./common --include=*.java | wc -l                             
>   # RA helpers
> {code}
> h2. What's left, by area
> ||Area||Classes||Tests||Blocked on||
> |Loan|57|470|nothing|
> |Savings and deposits|19|199|deposit helpers not written yet|
> |Organisation and misc|37|181|nothing|
> |Jobs and batch|5|69|nothing|
> |Client|9|55|nothing|
> |Accounting|11|40|nothing|
> |Datatable and entity|4|22|nothing|
> |Reporting, shares, bulkimport, group|10|36|nothing|
> |*Total*|*148*|*1,050*| |
> These six are big enough that each one needs its own PR:
> ||Class||Tests||Lines||
> |{{AdvancedPaymentAllocationLoanRepaymentScheduleTest}}|86|6,625|
> |{{ClientLoanIntegrationTest}}|66|8,354|
> |{{FixedDepositTest}}|47|3,200|
> |{{ClientSavingsIntegrationTest}}|45|3,662|
> |{{BatchApiTest}}|40|2,750|
> |{{RecurringDepositTest}}|38|3,128|
> h2. Old classes on the way out
> ||Class||Start||Now||Blocked on||
> |{{BaseLoanIntegrationTest}}|121|*53* (52 subclasses)|nothing|
> |{{BaseSavingsIntegrationTest}}|—|*3 subclasses*|savings batch|
> |{{ClientHelper}}|216|*170*|client batch|
> |{{LoanTransactionHelper}}|118|*125*|loan batch|
> |{{SavingsAccountHelper}}|37|*35*|savings batch|
> |{{Utils.java}}|309|*345*|everything else|
> |RestAssured-only helpers in {{common/}}|53|*52*|per-area Feign helpers|
> Worth flagging: {{Utils.java}} and {{LoanTransactionHelper}} both went 
> {*}up{*}, not down. New tests are still being written against the old layer 
> while I'm migrating the old ones off it.
> That's what exit criterion #4 is for.
> h2. Things I know are still open
> A few gaps I'd record:
>  * {{FeignLoanHelper}} still has a handful of methods that take a JSON string 
> and post it
> through the old RestAssured utility. Any test going down those paths isn't 
> genuinely off
> RestAssured, so the 135 figure above is slightly generous. Separate ticket 
> for it.
>  * One test living under the Feign folder still builds a RestAssured request 
> spec itself.
>  * {{FeignLoanTestBase}} is now 1,562 lines, 224 methods and 99 subclasses. 
> It's drifting
> towards being the same kind of god class I'm trying to delete. I'd rather 
> split it once the
> area batches have landed than churn it mid-migration.
> h2. How the Feign side is put together
> Helpers live under {{client/feign/helpers/}} (30 of them so far). Each takes 
> {{FineractFeignClient}} in the constructor, calls the API through {{ok(...)}} 
> / {{{}fail(...) }}from \{{{}FeignCalls{}}}, and returns the whole response 
> object rather than just an ID.
> Request building lives in {{client/feign/modules/}} (12 files: the 
> {{{}*RequestBuilders{}}}, {{{}LoanProductTemplates{}}}, 
> {{{}LoanTestValidators{}}}, test data holders). Tests extend 
> {{{}FeignIntegrationTest{}}}, {{FeignLoanTestBase}} or 
> {{{}FeignSavingsTestBase{}}}.
> Both clients are on the classpath at the same time. The {{exclude}} in 
> \{{dependencies.gradle }}keeps the duplicate model classes apart.
> Conventions I've settled on as I've gone:
>  * Feign helpers are new classes, not extra methods bolted onto the old 
> helpers
>  * Wrapper interfaces only where the generated name is unreadable 
> ({{{}create6(){}}} → {{{}createClient(){}}})
>  * New shared code goes in a helper or a module, never on the test base. 
> One-off methods stay {{private}} in the test that needs them.
>  * Where the generated model genuinely can't express a call, I drop to a 
> small raw-HTTP helper and leave a comment explaining why. Never RestAssured. 
> If the gap is only a field or two, I fix the Swagger DTO and regenerate 
> instead. I keep a running list of every one of these so none of them get 
> forgotten.
>  * Coexistence was the right call for the first phase. It ends when criterion 
> #4 lands.
> h2. PR roadmap
> I'm keeping the PR count deliberately low and putting the detail into commits 
> instead. Each
> remaining PR is one area, broken into commits that each build and pass on 
> their own, so they
> can be reviewed one at a time without the PR itself becoming unreviewable.
> ||PR||What||Files||Tests||Ticket||GitHub||Status||
> |1|Savings helper, test base, Swagger fields|—|—|FINERACT-2620, 2626|#5907, 
> #5934|Merged|
> |2|Client helper build-out, Swagger fields|—|—|FINERACT-2631, 2632|#5954, 
> #5955|Merged|
> |3|Charges and delinquency helpers|—|—|FINERACT-2635|#5978|Merged|
> |4|Loan helper: charges, transitions, 
> disbursement|—|—|FINERACT-2640|#5997|Merged|
> |5|Loan tests, 4 tiers|—|—|FINERACT-2649|4 PRs, see ticket|Last tier in 
> review|
> |6|Group and centre|3|16|FINERACT-2718|#6194|*In review — I'm here*|
> |7|Loan: money movement|21|360|to raise|—|Next|
> |8|Loan: lifecycle, product, COB|33|113|to raise|—|Not started|
> |9|Savings and deposits|20|209|to raise|—|Not started|
> |10|Client, charges, accounting|20|101|to raise|—|Not started|
> |11|Organisation, jobs, batch, config|33|228|to raise|—|Not started|
> |12|Closeout|—|—|to raise|—|Not started|
> |S1|Bulk import, shares, reporting, smoke tests|21|39|stretch|—|Not started|
> |S2|Split {{FeignLoanTestBase}}|—|—|stretch|—|Not started|
> |S3|The 50 Retrofit tests|50|—|stretch|—|Not started|
> PRs 7 to 11 add up to 127 files and 1,011 tests. S1 covers the last 21 files 
> and 39 tests.
> h2. Log
> One line per merge. I don't edit old entries, only add to the bottom.
> ||Date||PR||Ticket||What went in||
> |2026-06-04|[#5934|https://github.com/apache/fineract/pull/5934]|FINERACT-2626|Added
>  {{rejectedOnDate}} and {{withdrawnOnDate}} to the savings Swagger spec. The 
> generated model was missing them, so a reject call silently did nothing. 
> Needed before #5907 could land.|
> |2026-06-07|[#5907|https://github.com/apache/fineract/pull/5907]|FINERACT-2620|First
>  area done end to end. 10 new files: savings helper, test base, lifecycle 
> extension, request builders, and an 8-test lifecycle test to prove the 
> pattern works.|
> |2026-06-09|[#5955|https://github.com/apache/fineract/pull/5955]|FINERACT-2632|Client
>  Swagger fields the server accepts but the model didn't have: 
> {{{}submittedOnDate{}}}, the withdrawal fields, and 
> {{{}firstname{}}}/{{{}lastname{}}} on PUT.|
> |2026-06-09|[#5954|https://github.com/apache/fineract/pull/5954]|FINERACT-2631|{{FeignClientHelper}}
>  from 4 methods to 16, plus {{ClientRequestBuilders}} and a full client 
> lifecycle test.|
> |2026-06-11|[#5978|https://github.com/apache/fineract/pull/5978]|FINERACT-2635|Charges
>  and delinquency: {{FeignChargesHelper}} (14 methods), 
> {{{}ChargeRequestBuilders{}}}, and a 7-test delinquency lifecycle. Also fixed 
> 4 fields missing from {{PostChargesRequest}} that were sending nulls on PUT.|
> |2026-06-21|[#5997|https://github.com/apache/fineract/pull/5997]|FINERACT-2640|Loan
>  helper grew charge management, state transitions, disbursement details and 
> reschedule: 11 charge methods, 6 transitions, 4 disbursement methods.|
> |from 2026-06-26|4 PRs|FINERACT-2649|The loan test migration, done in four 
> tiers. Tier 4 is the big one at 92 files. Per-PR detail and review notes are 
> on that ticket rather than duplicated here. Final tier is in review.|
> |2026-07-28|[#6194|https://github.com/apache/fineract/pull/6194]|FINERACT-2718|Group
>  and centre. New helpers for group, centre, staff and GLIM. Migrated 
> {{{}CenterIntegrationTest{}}}, {{GroupTest}} and {{GroupLoanIntegrationTest}} 
> (16 tests) and retired a raw-HTTP stopgap helper that was Feign in name only. 
> No changes to the shared loan test base. In review.|



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to