# (DD37) Business Logic — ClinicServiceTests.shouldFindOwnersByLastName() [8 LOC]

| Field | Value |
|-------|-------|
| Fully Qualified Name | `org.springframework.samples.petclinic.service.ClinicServiceTests` |
| Layer | Service Test / Repository Validation |
| Module | `service` (Package: `org.springframework.samples.petclinic.service`) |

## 1. Role

### ClinicServiceTests.shouldFindOwnersByLastName()

This method verifies the owner lookup behavior exposed by the `OwnerRepository` when searching by last-name prefix. In business terms, it confirms that the system can locate multiple owner records for a common surname fragment and that the same search returns no records when the fragment does not match any stored owner data. The method acts as a focused repository contract test rather than an application workflow: it does not transform data or route between cases, but instead validates that the persistence query responds correctly to two representative customer search inputs.

The method exercises a read-only search pattern with two assertions: one positive match scenario and one negative no-result scenario. It serves as a regression safeguard for the owner-search capability that would typically back owner lookup screens and service-layer queries elsewhere in the application. Because the method uses the repository directly, it also demonstrates the expected query semantics for partial last-name matching, including how the repository behaves when the search prefix is misspelled or otherwise absent from the dataset.

## 2. Processing Pattern (Detailed Business Logic)

```mermaid
flowchart TD
    START(["shouldFindOwnersByLastName()"])
    READ1["Call this.owners.findByLastNameStartingWith(\"Davis\", pageable)"]
    ASSERT1["Assert result has size 2"]
    READ2["Call this.owners.findByLastNameStartingWith(\"Daviss\", pageable)"]
    ASSERT2["Assert result is empty"]
    END_NODE(["Return"])
    START --> READ1
    READ1 --> ASSERT1
    ASSERT1 --> READ2
    READ2 --> ASSERT2
    ASSERT2 --> END_NODE
```

**CRITICAL — Constant Resolution:**
No application constants are referenced in this method. The only literal inputs are the search strings `"Davis"` and `"Daviss"`, which are test data values rather than shared constants.

## 3. Parameter Analysis

| No | Parameter Name | Type | Business Description |
|----|---------------|------|---------------------|
| - | (none) | - | - |

External state read by the method:
- `this.owners` — injected `OwnerRepository` used to execute the owner search query.
- `pageable` — class field set to `Pageable.unpaged()` to request an unpaged result set.

## 4. CRUD Operations / Called Services

### Pre-computed evidence from code analysis graph:

| CRUD | SC / CBS | SC Code | Entity / DB | Operation Description |
|------|----------|---------|-------------|----------------------|
| R | `OwnerRepository.findByLastNameStartingWith` | OwnerRepository | Owner | Calls `findByLastNameStartingWith` in `OwnerRepository` |

Analyze all method calls within this method and classify each as a CRUD operation.
Use the pre-computed evidence above. If SC Code or Entity/DB is missing, try to infer from:
- The **SC Code** (Service Component code, e.g., `EKK0361A010SC`, `EKK1081D010CBS`) — look at the class name of the called method or its containing class.
- The **Entity/DB tables** — search for table name constants (often `KK_T_*` pattern), SQL references, or entity names in the called method's source code.

| CRUD | SC / CBS | SC Code | Entity / DB | Operation Description |
|------|----------|---------|-------------|----------------------|
| R | `OwnerRepository.findByLastNameStartingWith` | `OwnerRepository` | `Owner` | Reads owner records by last-name prefix and returns a page of matching owners |
| R | `assertThat(owners).hasSize(2)` | - | - | Verifies the query returns two owners for the matching search term |
| R | `assertThat(owners).isEmpty()` | - | - | Verifies the query returns no owners for the non-matching search term |

## 5. Dependency Trace

Trace who calls this method and what this method ultimately calls.
Use the pre-computed evidence and caller search results from Step 2 above.

| # | Caller (Screen/Batch) | Call Chain (Full Path to this Method) | Terminal (SC / CRUD / Entity) |
|---|----------------------|--------------------------------------|-------------------------------|
| 1 | Test runner / JUnit engine | `JUnit 5 runtime -> ClinicServiceTests.shouldFindOwnersByLastName()` | `OwnerRepository.findByLastNameStartingWith [R] Owner` |

## 6. Per-Branch Detail Blocks

**Block 1** — [SEQUENCE] (L88-L92)

> Executes two read queries against the owner repository and validates both the matching and non-matching search outcomes.

| # | Type | Code |
|---|------|------|
| 1 | CALL | `this.owners.findByLastNameStartingWith("Davis", pageable);` |
| 2 | SET | `owners = ...;` |
| 3 | CALL | `assertThat(owners).hasSize(2);` |
| 4 | CALL | `this.owners.findByLastNameStartingWith("Daviss", pageable);` |
| 5 | SET | `owners = ...;` |
| 6 | CALL | `assertThat(owners).isEmpty();` |
| 7 | RETURN | `void` method completes |

## 7. Glossary

| Term | Type | Business Meaning |
|------|------|------------------|
| `Owner` | Entity | Pet owner record stored in the clinic system |
| `OwnerRepository` | Repository | Persistence component that retrieves owner data from the database |
| `findByLastNameStartingWith` | Repository method | Search operation that returns owners whose last name begins with the supplied text |
| `Page` | Technical type | Container for paged query results |
| `Pageable` | Technical type | Pagination request object; here used as unpaged input |
| `unpaged` | Technical term | Query mode that returns all matching records without pagination |
| `last name` | Business term | Owner surname used as the search key in the repository query |
| `prefix search` | Business term | Partial-match lookup where input text must match the beginning of the stored last name |
| JUnit | Framework | Test execution framework used to run the method |
| AssertJ | Framework | Assertion library used to verify query results |
