GH GambleHub

Unit vs Integration Tests

1) Why distinguish between test types

Proper granulation of tests makes development predictable: Unit catch logic defects quickly and cheaply; Integration checks bundles of modules, real transport and "glue." Together, they reduce regression and accelerate releases.

2) Definitions and boundaries

Unit-test

Tests a small unit of behavior (function, class, use-case) in isolation.
External dependencies are replaced (mock/stub/fake).
Fast (ms-tens of ms), deterministic.

Integration test

Checks the interaction of several real components: database, broker (Kafka/RabbitMQ), HTTP/gRPC, file system, cache.
Minimum mocs, real protocols.
Slower (hundreds of ms-seconds), more expensive in support.

💡 Rule: as soon as "we go through the process/socket/DB" - we are already in integration waters.

3) Testing pyramid (not ice horn)

Foundation: Unit (70-80% in number) - cheap, fast.
Middle layer: Integration/Component (15-25%) - critical paths and contracts.
Top: E2E/UX/Exploratory (5-10%) - minimally enough.
On the sides: Static Analysis/Lint/Type check and Mutation testing as quality amplifiers.

4) What to give Unit and what to Integration

TaskTypeWhy
Pure business logic (validations, commission calculations, key idempotence)UnitFast, deterministic, many boundary values
Mappings DTO↔model, serialization, parsingUnitMany cases, easy to isolate
Repositories/ORM QueriesIntegration (с test DB)"Behavior" ORM and SQL nuances are visible only on a live database
HTTP contract (statuses, headers, schemas)Integration / ContractNeed a live HTTP + JSON Schema/OpenAPI stack
Saga/Outbox, Retras, DeadlinesIntegration / ComponentTimings, transactionality, broker
Rate limit в gatewayIntegrationRedis/state/timeouts
Payment webhooks (HMAC, repeat)Integration / CDCSignatures, hours, network features

5) Data and fixes

Unit

Inline fictions/builders (factory methods).
Table-driven tests for boundary values.
Property-based approach for invariants (e.g. "sum of debits = sum of credits").

Integration

Hermetic environment: Testcontainers/Docker Compose raise 'postgres + redis + kafka + wiremock'.
Initial seed in the database/cache and cleanup after (transaction/rollback, truncate).
Watches/timers are fake (controlled), otherwise flacks.

6) Tools and patterns

Mocks/Stubs/Fakes/Spies:
  • Stub is a fixed answer (cheap).
  • Mock - check interactions/number of calls.
  • Fake is a simplified implementation (for example, In-Memory Repo).
  • Contract testing (CDC): Pact/Swagger-based - fix customer expectations and check the provider.
  • WireMock/MockServer - HTTP stubs for third-party services.
  • Testcontainers are live DBs/brokers locally and in CI without a "zoo."

7) Examples

7. 1 Unit: Payment Idempotence (pseudocode)

python def test_idempotent_create_payment_returns_same_id():
repo = InMemoryPayments()
service = Payments(repo)

first = service. create(amount=100, key="abc")
second = service. create(amount=100, key="abc")

assert first. id == second. id assert repo. count() == 1

7. 2 Integration: Webhook Signature (HMAC) + Repeat

bash docker-compose: app + redis + wiremock (PSP)
docker compose -f docker-compose. test. yml up -d pytest -m "integration and webhook" -q
Test:
  • WireMock gives an event with an'X-Timestamp' and a signature.
  • The application checks HMAC, deduplicates by 'event _ id', repeat after 5 seconds does not create a double.
  • We check '200' and that there is only one entry.

7. 3 CDC: Customer contract to provider

The client generates a Pact (waiting: 'POST/v1/payout' → '201' with a diagram).
The provider in CI runs the verification of the contract at its stand.

8) Speed, parallelism, flakes

Units must run <100 ms per test; packet - seconds.
Integration - parallel by containers/ports; use startup migrations.

Flaky antidote:
  • controlled time (fake clock),
  • expectations "by explicit event," not 'sleep',
  • stable thresholds (retrai with jitter test deterministically).

9) Quality metrics

Coverage (lines/branches): useful for observing the trend, but not the target.
Mutation testing (PIT/Mutmut): Shows whether tests "kill" false changes - the real power of assassins.
Test duration and flaky rate: alerts at growth.
Defect containment: the proportion of bugs intercepted before production.

10) Embedding in CI/CD

Jobs: unit → integration → e2e (fan-out by service).
Dependency cache, parallel matrices by database/language/version.
Reports: JUnit/Allure + container log artifacts (for drops).
Gate: "green unit + critical integration" - merge condition; e2e - on nightly.

Matrix example (GitHub Actions, fragment):
yaml strategy:
matrix:
db: [postgres14, postgres16]
steps:
- run: docker run -d --name db -e POSTGRES_PASSWORD=pw postgres:${{ matrix. db }}
- run: pytest -m "unit" -q
- run: pytest -m "integration" -q

11) Microservices and Events

Service contracts: OpenAPI/Protobuf are versioned; compatibility tests (backward).

Event-driven:
  • Unit: domain event mapping and invariants.
  • Integration: publication/subscription in a real broker (Kafka), outbox/inbox semantics, exactly-once imitation (at least - idempotent).
  • Out-of-order tests.

12) Data and isolation in Integration

Each test → a unique schema/database (Testcontainers JDBC URL '? TC _ TMPFS =/var/lib/postgresql/data: rw').
Transactional fixes (begin→run→rollback) speed up cleaning.
For Redis/cache, the key prefix is' test: $ {RUN _ ID}: 'and' FLUSHDB'in teardown.

13) Specifics of iGaming/Finance

Money and limits: property-based tests for invariants (balance ≥ 0, total restrictions).
Regulatory: logging check (audit log is written), unchangeable events.
Payments/PSP: HMAC/mTLS integration tests, 'Retry-After', idempotency, dedup 'jti'.
Responsible play: threshold/cooldown rule tests; "vchera→segodnya" on fake clock.

14) Antipatterns

"Units" that raise DB/HTTP are already integration (confuse layers and slow down CI).
High coverage due to empty statements ("covered, but not checked").
Moki logic of third-party services where a contract is needed (breaks when updated).
Tests with 'sleep (5)' instead of event/condition expectations.
Common test database for parallel tests → race and flake.

15) Prod Readiness Checklist

  • Pyramid defined as% of Unit/Integration/E2E and target shares by run time.
  • Units are isolated, fast, cover boundary values ​ ​ and invariants.
  • Integration uses a hermetic environment (Testcontainers/Compose), without common states.
  • Contract tests (OpenAPI/Pact) are verified in CI.
  • Test data - managed: seed/rollback/prefixes, fake clock.
  • Parallel run, JUnit/Allure reports, container log artifacts.
  • Metrics: duration, flaky rate, mutation score; alerts to degradation.
  • Payment/webhook scenarios: HMAC/mTLS, retrai, idempotency, deadup.
  • Strategy documentation and sample test templates.

16) TL; DR

Unit - maximum logic, minimum environment; Integration - minimum moks, maximum realism. Hold the pyramid: Fast Units catch 80% of defects, Integration confirms bundles and contracts. Use hermetic containers, contract tests, fake clock and parallelism. Measure not only coverage, but also mutation score and flaky rate. Especially check the payment/webhook paths: signatures, retrays and idempotency.

Contact

Get in Touch

Reach out with any questions or support needs.We are always ready to help!

Start Integration

Email is required. Telegram or WhatsApp — optional.

Your Name optional
Email optional
Subject optional
Message optional
Telegram optional
@
If you include Telegram — we will reply there as well, in addition to Email.
WhatsApp optional
Format: +country code and number (e.g., +380XXXXXXXXX).

By clicking this button, you agree to data processing.