# (DD22) Business Logic — OwnerControllerTests.processUpdateOwnerFormHasErrors() [13 LOC]

| Field | Value |
|-------|-------|
| Fully Qualified Name | `org.springframework.samples.petclinic.owner.OwnerControllerTests` |
| Layer | Controller Test |
| Module | `owner` (Package: `org.springframework.samples.petclinic.owner`) |

## 1. Role

### OwnerControllerTests.processUpdateOwnerFormHasErrors()

This test method verifies the negative path of the owner update workflow in the PetClinic web layer. It submits an edit request for an existing owner with required address data intentionally omitted, then confirms that the MVC layer rejects the form submission and redisplays the owner maintenance form instead of persisting the change. Business-wise, it validates that owner master data cannot be updated with incomplete contact information, protecting the integrity of the owner profile used throughout the clinic application.

The method exercises the validation-and-rejection branch of the controller contract rather than a successful CRUD update. It ensures that field-level validation errors are attached to the `owner` model object for `address` and `telephone`, which are the business fields missing from the submitted request. The test also verifies that the user stays on the same create/update view so the missing values can be corrected without losing context. As a controller test, its role is to assert that request binding, validation, and view resolution work together as expected for the owner edit screen.

## 2. Processing Pattern (Detailed Business Logic)

```mermaid
flowchart TD
    START(["processUpdateOwnerFormHasErrors() test start"])
    REQ(["Build POST request /owners/{ownerId}/edit with ownerId=1"])
    SET_FIRST(["Set firstName = Joe"])
    SET_LAST(["Set lastName = Bloggs"])
    SET_ADDRESS(["Set address = empty string"])
    SET_TELEPHONE(["Set telephone = empty string"])
    PERFORM(["Submit request through MockMvc"])
    ASSERT_OK(["Assert HTTP status is 200 OK"])
    ASSERT_ERRORS(["Assert model has validation errors for owner"])
    ASSERT_ADDRESS(["Assert field error on owner.address"])
    ASSERT_TELEPHONE(["Assert field error on owner.telephone"])
    ASSERT_VIEW(["Assert view owners/createOrUpdateOwnerForm"])
    END_NODE(["Test passes"])

    START --> REQ
    REQ --> SET_FIRST
    SET_FIRST --> SET_LAST
    SET_LAST --> SET_ADDRESS
    SET_ADDRESS --> SET_TELEPHONE
    SET_TELEPHONE --> PERFORM
    PERFORM --> ASSERT_OK
    ASSERT_OK --> ASSERT_ERRORS
    ASSERT_ERRORS --> ASSERT_ADDRESS
    ASSERT_ADDRESS --> ASSERT_TELEPHONE
    ASSERT_TELEPHONE --> ASSERT_VIEW
    ASSERT_VIEW --> END_NODE
```

**Constant Resolution:**
- No constant-driven branches are present in this method.
- `TEST_OWNER_ID` is a local test fixture value resolved in the class as `1`.

## 3. Parameter Analysis

| No | Parameter Name | Type | Business Description |
|----|---------------|------|---------------------|
| - | (none) | - | This JUnit test method has no parameters. It operates only on the fixed test fixture state and the locally constructed MockMvc request payload. |

Instance fields or external state read by the method:
- `mockMvc` - the configured MVC test client used to submit the request and verify the response.
- `TEST_OWNER_ID` - the owner identifier used in the request path.

## 4. CRUD Operations / Called Services

This method does not call application CRUD services directly. It is a test harness that drives the controller through HTTP and asserts on the resulting MVC response. The observed behavior corresponds to a rejected Update flow because the owner edit form is submitted with invalid/missing data.

| CRUD | SC / CBS | SC Code | Entity / DB | Operation Description |
|------|----------|---------|-------------|----------------------|
| U | `MockMvc.perform(post("/owners/{ownerId}/edit", TEST_OWNER_ID)... )` | N/A | `Owner` form binding | Submits an owner update request with missing address and telephone values, causing validation failure instead of persistence. |
| R | `model().attributeHasErrors("owner")` and field error assertions | N/A | `Owner` | Reads the validation result produced by the MVC binding layer to confirm rejected update data. |

## 5. Dependency Trace

| # | Caller (Screen/Batch) | Call Chain (Full Path to this Method) | Terminal (SC / CRUD / Entity) |
|---|----------------------|--------------------------------------|-------------------------------|
| 1 | Screen test: `OwnerControllerTests` | `OwnerControllerTests.processUpdateOwnerFormHasErrors` | `MockMvc POST /owners/{ownerId}/edit [U] Owner form binding` |

## 6. Per-Branch Detail Blocks

**Block 1** — [SEQUENCE] `processUpdateOwnerFormHasErrors()` (L202-L214)

> This block represents a single linear test flow with no conditional branching.

| # | Type | Code |
|---|------|------|
| 1 | EXEC | `mockMvc.perform(post("/owners/{ownerId}/edit", TEST_OWNER_ID)... )` // Build and submit the edit request |
| 2 | EXEC | `.param("firstName", "Joe")` // Provide owner first name |
| 3 | EXEC | `.param("lastName", "Bloggs")` // Provide owner last name |
| 4 | EXEC | `.param("address", "")` // Submit empty address to trigger validation |
| 5 | EXEC | `.param("telephone", "")` // Submit empty telephone to trigger validation |
| 6 | CALL | `.andExpect(status().isOk())` // Verify form redisplay after validation failure |
| 7 | CALL | `.andExpect(model().attributeHasErrors("owner"))` // Verify owner model contains validation errors |
| 8 | CALL | `.andExpect(model().attributeHasFieldErrors("owner", "address"))` // Verify address field rejection |
| 9 | CALL | `.andExpect(model().attributeHasFieldErrors("owner", "telephone"))` // Verify telephone field rejection |
| 10 | CALL | `.andExpect(view().name("owners/createOrUpdateOwnerForm"))` // Verify same owner maintenance view is returned |
| 11 | RETURN | `void` // Test completes after assertions |

## 7. Glossary

| Term | Type | Business Meaning |
|------|------|------------------|
| `Owner` | Entity | Clinic customer profile representing the pet owner whose contact data is maintained in the system. |
| `owner` | Model attribute | MVC form backing object for the owner create/update screen. |
| `address` | Field | Owner mailing address; required contact detail for account and clinic communication. |
| `telephone` | Field | Owner phone number; required contact detail used to reach the owner. |
| `firstName` | Field | Owner given name shown on the customer profile. |
| `lastName` | Field | Owner family name used to identify and search the customer record. |
| `ownerId` | Identifier | Persistent identifier for the owner record being edited. |
| `MockMvc` | Technical term | Spring MVC test client used to simulate browser requests and verify controller behavior. |
| `validation` | Business term | Form input checking that prevents saving incomplete or invalid owner data. |
| `createOrUpdateOwnerForm` | View name | UI page used for both creating a new owner and editing an existing owner. |
| CRUD | Acronym | Create, Read, Update, Delete — standard data operation categories. |
