# Org / Springframework / Samples / Petclinic / Service

## Overview

The `org.springframework.samples.petclinic.service` package contains the test-side service/repository coverage for Petclinic. Its main purpose is to verify that repository-backed operations behave correctly for owners, pets, visits, pet types, and vets, including persistence, relationship handling, and lookup behavior.

This module appears to exist as an integration-focused safety net: instead of mocking persistence, the tests exercise the real JPA repositories against a configured database so developers can confirm that domain mappings and repository methods still work end to end.

## Key Classes and Interfaces

### [ClinicServiceTests](src/test/java/org/springframework/samples/petclinic/service/ClinicServiceTests.java:70)

`ClinicServiceTests` is the central test class in this package. It is annotated with `@DataJpaTest`, so it loads a JPA-focused Spring test slice and wires in real repository beans. The test class directly exercises three repositories:

- `OwnerRepository` for owner, pet, and visit flows
- `PetTypeRepository` for pet type lookup
- `VetRepository` for vet lookup

The class is intentionally stateful only through injected repositories and a shared `Pageable.unpaged()` instance. Each test method focuses on one behavior of the persistence layer:

- owner search by last name prefix
- loading a single owner with associated pet data
- inserting and updating owners
- listing pet types
- inserting and updating pets through an owner aggregate
- listing vets and specialty data
- adding visits and loading visits for a pet

Because several tests are marked `@Transactional`, they can modify database state and rely on transaction rollback to keep the test database clean.

#### Important methods

- [shouldFindOwnersByLastName()](src/test/java/org/springframework/samples/petclinic/service/ClinicServiceTests.java:87) — Queries `OwnerRepository.findByLastNameStartingWith("Davis", pageable)` and verifies that two owners are returned. It then checks that a non-matching prefix returns an empty page. This confirms repository filtering and paging behavior.
- [shouldFindSingleOwnerWithPet()](src/test/java/org/springframework/samples/petclinic/service/ClinicServiceTests.java:96) — Loads owner `1` and verifies that the owner exists, the last name begins with `Franklin`, and the owner has one pet whose type is present and named `cat`. This is a smoke test for entity graph/association loading.
- [shouldInsertOwner()](src/test/java/org/springframework/samples/petclinic/service/ClinicServiceTests.java:107) — Creates a new `Owner`, saves it, checks that an id is assigned, and then confirms that the matching last-name query returns one more row than before. The method demonstrates repository save semantics and generated identifiers.
- [shouldUpdateOwner()](src/test/java/org/springframework/samples/petclinic/service/ClinicServiceTests.java:126) — Loads owner `1`, changes the last name, saves the owner, then re-reads it from the repository to ensure the change is persisted. This validates update behavior rather than only in-memory mutation.
- [shouldFindAllPetTypes()](src/test/java/org/springframework/samples/petclinic/service/ClinicServiceTests.java:145) — Retrieves all pet types, then uses `EntityUtils.getById(...)` to locate id `1` and id `4`. It asserts the names `cat` and `snake`, confirming seed data and lookup order-independent access.
- [shouldInsertPetIntoDatabaseAndGenerateId()](src/test/java/org/springframework/samples/petclinic/service/ClinicServiceTests.java:155) — Loads owner `6`, creates a new `Pet`, assigns a `PetType`, sets a birth date, and adds it through `owner.addPet(pet)`. After saving the owner, it reloads the owner and verifies the new pet exists and has a generated id. This covers cascading persistence through the owner aggregate.
- [shouldUpdatePetName()](src/test/java/org/springframework/samples/petclinic/service/ClinicServiceTests.java:183) — Loads owner `6`, finds pet `7`, changes the pet name, saves the owner, and verifies the persisted pet name changed after reload. This confirms updates on nested entities.
- [shouldFindVets()](src/test/java/org/springframework/samples/petclinic/service/ClinicServiceTests.java:204) — Loads all vets and uses `EntityUtils.getById(...)` to find vet `3`. It verifies the last name `Douglas`, two specialties, and specialty names `dentistry` and `surgery`.
- [shouldAddNewVisitForPet()](src/test/java/org/springframework/samples/petclinic/service/ClinicServiceTests.java:215) — Loads owner `6`, gets pet `7`, creates a `Visit`, adds it through `owner6.addVisit(pet7.getId(), visit)`, saves the owner, and asserts that the visit collection grew by one and that the new visit received an id. This exercises the domain helper used for visit creation.
- [shouldFindVisitsByPetId()](src/test/java/org/springframework/samples/petclinic/service/ClinicServiceTests.java:235) — Loads owner `6`, gets pet `7`, and verifies that the pet has two visits and that the first visit has a non-null date. This is a read-side verification for visit associations.

### [EntityUtils](src/test/java/org/springframework/samples/petclinic/service/EntityUtils.java:33)

`EntityUtils` is a small helper class used by the tests to search a collection of entities by id. It is declared `abstract` only as a utility container; it has no state and no instances are needed.

The class exists separately from `BaseEntity` because it depends on `ObjectRetrievalFailureException`, which is part of the ORM/persistence layer rather than the model layer. Keeping this helper in the service test package lets tests perform id-based lookups without duplicating boilerplate search logic.

#### Important methods

- [getById(Collection<T> entities, Class<T> entityClass, int entityId)](src/test/java/org/springframework/samples/petclinic/service/EntityUtils.java:43) — Iterates through the provided collection and returns the first entity whose id matches `entityId` and whose runtime type is compatible with `entityClass`. If no match is found, it throws `ObjectRetrievalFailureException`. Tests use this to make assertions against known seed entities without depending on collection order.

## How It Works

The package follows a straightforward repository-integration testing pattern:

1. Spring starts a JPA test slice via `@DataJpaTest`.
2. The repositories are injected into `ClinicServiceTests`.
3. Each test loads known database fixtures by id or searches by a known prefix.
4. The test mutates or inspects the domain objects.
5. For write tests, the code saves the aggregate root back through `OwnerRepository`.
6. The test reloads the entity from the repository to verify the persistence result.

A few patterns stand out:

- **Aggregate-root saving**: pet and visit changes are saved by calling `owners.save(owner)`, not by persisting `Pet` or `Visit` directly. That suggests the owner is the aggregate root for these relationships.
- **Explicit reloads**: write tests usually re-query the repository after saving. This avoids false positives from in-memory entity state.
- **Id-based fixture assertions**: the tests refer to known ids such as `1`, `3`, `6`, and `7`, so they depend on a seeded dataset.
- **Helper-based lookup**: `EntityUtils.getById(...)` is used when tests need stable selection from a collection.

### Main repository flow for adding a pet

```mermaid
flowchart LR
ServiceTests["ClinicServiceTests"] --> OwnerRepository["OwnerRepository"]
ServiceTests --> PetTypeRepository["PetTypeRepository"]
ServiceTests --> EntityUtils["EntityUtils"]
OwnerRepository --> Owner["Owner"]
Owner --> Pet["Pet"]
Pet --> PetType["PetType"]
Pet --> Visit["Visit"]
```

In the pet insertion test, the flow is roughly:

1. Load owner `6`.
2. Look up a `PetType` from the available types.
3. Create and configure a new `Pet`.
4. Add the pet to the owner via `owner.addPet(pet)`.
5. Save the owner through `OwnerRepository`.
6. Reload the owner and confirm the pet id was generated.

The visit test uses the same overall shape, except it adds a `Visit` to an existing pet and then verifies the collection and generated identifier.

## Data Model

This package does not define production entities itself, but the tests reveal the shape of the Petclinic domain model used by the repositories:

- **Owner** owns a collection of **Pet** objects.
- **Pet** has a **PetType** and a collection of **Visit** objects.
- **Vet** has a collection of specialties.
- The helper `EntityUtils` expects all entities to extend `BaseEntity` and expose an `id`.

The tests also imply these relationships and behaviors:

- An owner can be found by last-name prefix.
- A pet belongs to exactly one owner.
- A pet type is selected from a catalog of reference data.
- A visit belongs to a pet and receives an id after persistence.
- Vet data includes specialties that can be verified by name.

## Dependencies and Integration

The package depends on several parts of the application:

- **`org.springframework.samples.petclinic.owner`** — owner, pet, pet type, and visit domain/repository APIs
- **`org.springframework.samples.petclinic.vet`** — vet domain/repository APIs
- **`org.springframework.samples.petclinic.model`** — shared base entity contract used by `EntityUtils`
- **Spring Boot Test / Spring Data JPA** — used to load the repository test slice and manage transactions
- **`ObjectRetrievalFailureException`** — raised by `EntityUtils` when an entity id cannot be found

The package is tightly coupled to the test database setup because it relies on known seed data. The assertions are intentionally specific to that dataset.

## Notes for Developers

- These tests are integration tests, not unit tests. They validate persistence mappings and repository behavior against a real database configuration.
- Several assertions depend on hard-coded fixture ids and names. If the seed data changes, these tests will need to be updated together.
- `EntityUtils.getById(...)` throws if it cannot find a matching entity. Use it when missing data should fail fast rather than when absence is expected.
- Write operations should usually go through `OwnerRepository.save(...)` on the aggregate root rather than saving nested objects directly.
- `@Transactional` on mutation tests keeps the database clean after each method, which is important when inserting or updating persistent state.
- `@AutoConfigureTestDatabase(replace = Replace.NONE)` indicates the tests should not silently swap away from the configured database. That makes the test behavior closer to the intended runtime database environment.

