diff --git a/src/main/java/net/hostsharing/hsadminng/hs/office/partner/EntityPatch.java b/src/main/java/net/hostsharing/hsadminng/hs/office/partner/EntityPatch.java
new file mode 100644
index 00000000..b9ec6ac5
--- /dev/null
+++ b/src/main/java/net/hostsharing/hsadminng/hs/office/partner/EntityPatch.java
@@ -0,0 +1,6 @@
+package net.hostsharing.hsadminng.hs.office.partner;
+
+public interface EntityPatch<R> {
+
+    void apply(R resource);
+}
diff --git a/src/main/java/net/hostsharing/hsadminng/hs/office/partner/HsOfficePartnerEntityPatch.java b/src/main/java/net/hostsharing/hsadminng/hs/office/partner/HsOfficePartnerEntityPatch.java
index 90053ff5..96aa5137 100644
--- a/src/main/java/net/hostsharing/hsadminng/hs/office/partner/HsOfficePartnerEntityPatch.java
+++ b/src/main/java/net/hostsharing/hsadminng/hs/office/partner/HsOfficePartnerEntityPatch.java
@@ -9,8 +9,9 @@ import java.util.NoSuchElementException;
 import java.util.Optional;
 import java.util.UUID;
 import java.util.function.Function;
+import java.util.function.Supplier;
 
-class HsOfficePartnerEntityPatch {
+class HsOfficePartnerEntityPatch implements EntityPatch<HsOfficePartnerPatchResource> {
 
     private final HsOfficePartnerEntity entity;
     private final Function<UUID, Optional<HsOfficeContactEntity>> fetchContact;
@@ -25,16 +26,17 @@ class HsOfficePartnerEntityPatch {
         this.fetchPerson = fetchPerson;
     }
 
-    void apply(final HsOfficePartnerPatchResource resource) {
+    @Override
+    public void apply(final HsOfficePartnerPatchResource resource) {
         OptionalFromJson.of(resource.getContactUuid()).ifPresent(newValue -> {
-            entity.setContact(fetchContact.apply(newValue).orElseThrow(
-                    () -> new NoSuchElementException("cannot find contact uuid " + newValue)
-            ));
+            verifyNotNull(newValue, "contact");
+            entity.setContact(fetchContact.apply(newValue)
+                    .orElseThrow(noSuchElementException("contact", newValue)));
         });
         OptionalFromJson.of(resource.getPersonUuid()).ifPresent(newValue -> {
-            entity.setPerson(fetchPerson.apply(newValue).orElseThrow(
-                    () -> new NoSuchElementException("cannot find person uuid " + newValue)
-            ));
+            verifyNotNull(newValue, "person");
+            entity.setPerson(fetchPerson.apply(newValue)
+                    .orElseThrow(noSuchElementException("person", newValue)));
         });
         OptionalFromJson.of(resource.getRegistrationOffice()).ifPresent(entity::setRegistrationOffice);
         OptionalFromJson.of(resource.getRegistrationNumber()).ifPresent(entity::setRegistrationNumber);
@@ -42,4 +44,14 @@ class HsOfficePartnerEntityPatch {
         OptionalFromJson.of(resource.getBirthName()).ifPresent(entity::setBirthName);
         OptionalFromJson.of(resource.getDateOfDeath()).ifPresent(entity::setDateOfDeath);
     }
+
+    private Supplier<RuntimeException> noSuchElementException(final String propertyName, final UUID newValue) {
+        return () -> new NoSuchElementException("cannot find '" + propertyName + "' uuid " + newValue);
+    }
+
+    private void verifyNotNull(final UUID newValue, final String propertyName) {
+        if (newValue == null) {
+            throw new IllegalArgumentException("property '" + propertyName + "' must not be null");
+        }
+    }
 }
diff --git a/src/test/java/net/hostsharing/hsadminng/hs/office/partner/HsOfficePartnerEntityPatchUnitTest.java b/src/test/java/net/hostsharing/hsadminng/hs/office/partner/HsOfficePartnerEntityPatchUnitTest.java
index 7c103dd4..9bba6ea1 100644
--- a/src/test/java/net/hostsharing/hsadminng/hs/office/partner/HsOfficePartnerEntityPatchUnitTest.java
+++ b/src/test/java/net/hostsharing/hsadminng/hs/office/partner/HsOfficePartnerEntityPatchUnitTest.java
@@ -3,23 +3,20 @@ package net.hostsharing.hsadminng.hs.office.partner;
 import net.hostsharing.hsadminng.hs.office.contact.HsOfficeContactEntity;
 import net.hostsharing.hsadminng.hs.office.generated.api.v1.model.HsOfficePartnerPatchResource;
 import net.hostsharing.hsadminng.hs.office.person.HsOfficePersonEntity;
-import org.junit.jupiter.api.Test;
-import org.junit.jupiter.params.ParameterizedTest;
-import org.junit.jupiter.params.provider.EnumSource;
-import org.junit.jupiter.params.provider.NullSource;
-import org.junit.jupiter.params.provider.ValueSource;
-import org.openapitools.jackson.nullable.JsonNullable;
+import org.junit.jupiter.api.TestInstance;
 
 import java.time.LocalDate;
-import java.util.NoSuchElementException;
 import java.util.Optional;
 import java.util.UUID;
+import java.util.stream.Stream;
 
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.catchThrowableOfType;
+import static org.junit.jupiter.api.TestInstance.Lifecycle.PER_CLASS;
 
-// TODO: there must be an easier way to test such patch classes
-class HsOfficePartnerEntityPatchUnitTest {
+@TestInstance(PER_CLASS)
+class HsOfficePartnerEntityPatchUnitTest extends PatchUnitTestBase<
+        HsOfficePartnerPatchResource,
+        HsOfficePartnerEntity
+        > {
 
     private static final UUID INITIAL_PARTNER_UUID = UUID.randomUUID();
     private static final UUID INITIAL_CONTACT_UUID = UUID.randomUUID();
@@ -31,198 +28,84 @@ class HsOfficePartnerEntityPatchUnitTest {
     private static final LocalDate PATCHED_BIRTHDAY = LocalDate.parse("1990-12-31");
 
     private static final LocalDate INITIAL_DAY_OF_DEATH = LocalDate.parse("2000-01-01");
-    private static final LocalDate PATCHED_DAY_OF_DEATH = LocalDate.parse("2022-08-31");
+    private static final LocalDate PATCHED_DATE_OF_DEATH = LocalDate.parse("2022-08-31");
 
-    final HsOfficePartnerEntity givenPartner = new HsOfficePartnerEntity();
-    private final HsOfficePersonEntity givenInitialPerson = new HsOfficePersonEntity();
-    private final HsOfficeContactEntity givenInitialContact = new HsOfficeContactEntity();
+    private final HsOfficePersonEntity givenInitialPerson = HsOfficePersonEntity.builder()
+            .uuid(INITIAL_PERSON_UUID)
+            .build();
+    private final HsOfficeContactEntity givenInitialContact = HsOfficeContactEntity.builder()
+            .uuid(INITIAL_CONTACT_UUID)
+            .build();
 
-    final HsOfficePartnerPatchResource patchResource = new HsOfficePartnerPatchResource();
-
-    private final HsOfficePartnerEntityPatch hsOfficePartnerEntityPatch = new HsOfficePartnerEntityPatch(
-            givenPartner,
-            uuid -> uuid == PATCHED_CONTACT_UUID
-                    ? Optional.of(newContact(uuid))
-                    : Optional.empty(),
-            uuid -> uuid == PATCHED_PERSON_UUID
-                    ? Optional.of(newPerson(uuid))
-                    : Optional.empty());
-
-    {
-        givenInitialPerson.setUuid(INITIAL_PERSON_UUID);
-        givenInitialContact.setUuid(INITIAL_CONTACT_UUID);
-
-        givenPartner.setUuid(INITIAL_PARTNER_UUID);
-        givenPartner.setPerson(givenInitialPerson);
-        givenPartner.setContact(givenInitialContact);
-        givenPartner.setRegistrationOffice("initial Reg-Office");
-        givenPartner.setRegistrationNumber("initial Reg-Number");
-        givenPartner.setBirthday(INITIAL_BIRTHDAY);
-        givenPartner.setBirthName("initial birth name");
-        givenPartner.setDateOfDeath(INITIAL_DAY_OF_DEATH);
+    @Override
+    HsOfficePartnerEntity newInitialEntity() {
+        final var p = new HsOfficePartnerEntity();
+        p.setUuid(INITIAL_PARTNER_UUID);
+        p.setPerson(givenInitialPerson);
+        p.setContact(givenInitialContact);
+        p.setRegistrationOffice("initial Reg-Office");
+        p.setRegistrationNumber("initial Reg-Number");
+        p.setBirthday(INITIAL_BIRTHDAY);
+        p.setBirthName("initial birth name");
+        p.setDateOfDeath(INITIAL_DAY_OF_DEATH);
+        return p;
     }
 
-    @Test
-    void willPatchAllProperties() {
-        // given
-        patchResource.setContactUuid(JsonNullable.of(PATCHED_CONTACT_UUID));
-        patchResource.setPersonUuid(JsonNullable.of(PATCHED_PERSON_UUID));
-        patchResource.setRegistrationNumber(JsonNullable.of("patched Reg-Number"));
-        patchResource.setRegistrationOffice(JsonNullable.of("patched Reg-Office"));
-        patchResource.setBirthday(JsonNullable.of(PATCHED_BIRTHDAY));
-        patchResource.setBirthName(JsonNullable.of("patched birth name"));
-        patchResource.setDateOfDeath(JsonNullable.of(PATCHED_DAY_OF_DEATH));
-
-        // when
-        hsOfficePartnerEntityPatch.apply(patchResource);
-
-        // then
-        new HsOfficePartnerEntityMatcher()
-                .withPatchedContactUuid(PATCHED_CONTACT_UUID)
-                .withPatchedPersonUuid(PATCHED_PERSON_UUID)
-                .withPatchedRegistrationOffice("patched Reg-Office")
-                .withPatchedRegistrationNumber("patched Reg-Number")
-                .withPatchedBirthday(PATCHED_BIRTHDAY)
-                .withPatchedBirthName("patched birth name")
-                .withPatchedDateOfDeath(PATCHED_DAY_OF_DEATH)
-                .matches(givenPartner);
+    @Override
+    HsOfficePartnerPatchResource newPatchResource() {
+        return new HsOfficePartnerPatchResource();
     }
 
-    @Test
-    void willThrowIfNoContactFound() {
-        // given
-        patchResource.setContactUuid(JsonNullable.of(null));
-
-        // when
-        final var exception = catchThrowableOfType(() -> {
-            hsOfficePartnerEntityPatch.apply(patchResource);
-        }, NoSuchElementException.class);
-
-        // then
-        assertThat(exception.getMessage()).isEqualTo("cannot find contact uuid null");
+    @Override
+    HsOfficePartnerEntityPatch createPatcher(final HsOfficePartnerEntity partner) {
+        return new HsOfficePartnerEntityPatch(
+                partner,
+                uuid -> uuid == PATCHED_CONTACT_UUID
+                        ? Optional.of(newContact(uuid))
+                        : Optional.empty(),
+                uuid -> uuid == PATCHED_PERSON_UUID
+                        ? Optional.of(newPerson(uuid))
+                        : Optional.empty());
     }
 
-    @Test
-    void willThrowIfNoPersonFound() {
-        // given
-        patchResource.setPersonUuid(JsonNullable.of(null));
-
-        // when
-        final var exception = catchThrowableOfType(() -> {
-            hsOfficePartnerEntityPatch.apply(patchResource);
-        }, NoSuchElementException.class);
-
-        // then
-        assertThat(exception.getMessage()).isEqualTo("cannot find person uuid null");
+    @Override
+    Stream<TestCase> testCases() {
+        return Stream.of(
+                new TestCase(
+                        "contact",
+                        HsOfficePartnerPatchResource::setContactUuid,
+                        PATCHED_CONTACT_UUID,
+                        HsOfficePartnerEntity::setContact,
+                        newContact(PATCHED_CONTACT_UUID))
+                        .notNullable()
+                        .resolvesUuid(),
+                new TestCase(
+                        "person",
+                        HsOfficePartnerPatchResource::setPersonUuid,
+                        PATCHED_PERSON_UUID,
+                        HsOfficePartnerEntity::setPerson,
+                        newPerson(PATCHED_PERSON_UUID))
+                        .notNullable()
+                        .resolvesUuid(),
+                new TestCase(
+                        "registrationOffice",
+                        HsOfficePartnerPatchResource::setRegistrationOffice,
+                        "patched Reg-Office",
+                        HsOfficePartnerEntity::setRegistrationOffice),
+                new TestCase(
+                        "birthday",
+                        HsOfficePartnerPatchResource::setBirthday,
+                        PATCHED_BIRTHDAY,
+                        HsOfficePartnerEntity::setBirthday),
+                new TestCase(
+                        "dayOfDeath",
+                        HsOfficePartnerPatchResource::setDateOfDeath,
+                        PATCHED_DATE_OF_DEATH,
+                        HsOfficePartnerEntity::setDateOfDeath)
+        );
     }
 
-    @Test
-    void willPatchOnlyContactProperty() {
-        // given
-        patchResource.setContactUuid(JsonNullable.of(PATCHED_CONTACT_UUID));
-
-        // when
-        hsOfficePartnerEntityPatch.apply(patchResource);
-
-        // then
-        new HsOfficePartnerEntityMatcher()
-                .withPatchedContactUuid(PATCHED_CONTACT_UUID)
-                .matches(givenPartner);
-    }
-
-    @Test
-    void willPatchOnlyPersonProperty() {
-        // given
-        patchResource.setPersonUuid(JsonNullable.of(PATCHED_PERSON_UUID));
-
-        // when
-        hsOfficePartnerEntityPatch.apply(patchResource);
-
-        // then
-        new HsOfficePartnerEntityMatcher()
-                .withPatchedPersonUuid(PATCHED_PERSON_UUID)
-                .matches(givenPartner);
-    }
-
-    @ParameterizedTest
-    @ValueSource(strings = { "patched Reg-Office" })
-    @NullSource
-    void willPatchOnlyRegOfficeProperty(final String patchedValue) {
-        // given
-        patchResource.setRegistrationOffice(JsonNullable.of(patchedValue));
-
-        // when
-        hsOfficePartnerEntityPatch.apply(patchResource);
-
-        // then
-        new HsOfficePartnerEntityMatcher()
-                .withPatchedRegistrationOffice(patchedValue)
-                .matches(givenPartner);
-    }
-
-    @ParameterizedTest
-    @ValueSource(strings = { "patched birth name" })
-    @NullSource
-    void willPatchOnlyRegNumberProperty(final String patchedValue) {
-        // given
-        patchResource.setRegistrationNumber(JsonNullable.of(patchedValue));
-
-        // when
-        hsOfficePartnerEntityPatch.apply(patchResource);
-
-        // then
-        new HsOfficePartnerEntityMatcher()
-                .withPatchedRegistrationNumber(patchedValue)
-                .matches(givenPartner);
-    }
-
-    @ParameterizedTest
-    @EnumSource(LocalDatePatches.class)
-    void willPatchOnlyBirthdayProperty(final LocalDatePatches patch) {
-        // given
-        patchResource.setBirthday(JsonNullable.of(patch.value));
-
-        // when
-        hsOfficePartnerEntityPatch.apply(patchResource);
-
-        // then
-        new HsOfficePartnerEntityMatcher()
-                .withPatchedBirthday(patch.value)
-                .matches(givenPartner);
-    }
-
-    @ParameterizedTest
-    @ValueSource(strings = { "patched birth name" })
-    @NullSource
-    void willPatchOnlyBirthNameProperty(final String patchedValue) {
-        // given
-        patchResource.setBirthName(JsonNullable.of(patchedValue));
-
-        // when
-        hsOfficePartnerEntityPatch.apply(patchResource);
-
-        // then
-        new HsOfficePartnerEntityMatcher()
-                .withPatchedBirthName(patchedValue)
-                .matches(givenPartner);
-    }
-
-    @ParameterizedTest
-    @EnumSource(LocalDatePatches.class)
-    void willPatchOnlyDateOfDeathProperty(final LocalDatePatches patch) {
-        // given
-        patchResource.setDateOfDeath(JsonNullable.of(patch.value));
-
-        // when
-        hsOfficePartnerEntityPatch.apply(patchResource);
-
-        // then
-        new HsOfficePartnerEntityMatcher()
-                .withPatchedDateOfDeath(patch.value)
-                .matches(givenPartner);
-    }
-
-    private HsOfficeContactEntity newContact(final UUID uuid) {
+    private static HsOfficeContactEntity newContact(final UUID uuid) {
         final var newContact = new HsOfficeContactEntity();
         newContact.setUuid(uuid);
         return newContact;
@@ -233,75 +116,4 @@ class HsOfficePartnerEntityPatchUnitTest {
         newPerson.setUuid(uuid);
         return newPerson;
     }
-
-    private static class HsOfficePartnerEntityMatcher {
-
-        private UUID expectedContactUuid = INITIAL_CONTACT_UUID;
-        private UUID expectedPersonUuid = INITIAL_PERSON_UUID;
-        private String expectedRegOffice = "initial Reg-Office";
-        private String expectedRegNumber = "initial Reg-Number";
-        private LocalDate expectedBirthday = INITIAL_BIRTHDAY;
-        private String expectedBirthName = "initial birth name";
-        private LocalDate expectedDateOfDeath = INITIAL_DAY_OF_DEATH;
-
-        HsOfficePartnerEntityMatcher withPatchedContactUuid(final UUID patchedContactUuid) {
-            expectedContactUuid = patchedContactUuid;
-            return this;
-        }
-
-        HsOfficePartnerEntityMatcher withPatchedPersonUuid(final UUID patchedPersonUuid) {
-            expectedPersonUuid = patchedPersonUuid;
-            return this;
-        }
-
-        HsOfficePartnerEntityMatcher withPatchedRegistrationOffice(final String patchedRegOffice) {
-            expectedRegOffice = patchedRegOffice;
-            return this;
-        }
-
-        HsOfficePartnerEntityMatcher withPatchedRegistrationNumber(final String patchedRegNumber) {
-            expectedRegNumber = patchedRegNumber;
-            return this;
-        }
-
-        HsOfficePartnerEntityMatcher withPatchedBirthday(final LocalDate patchedBirthday) {
-            expectedBirthday = patchedBirthday;
-            return this;
-        }
-
-        HsOfficePartnerEntityMatcher withPatchedBirthName(final String patchedBirthName) {
-            expectedBirthName = patchedBirthName;
-            return this;
-        }
-
-        HsOfficePartnerEntityMatcher withPatchedDateOfDeath(final LocalDate patchedDayOfDeath) {
-            expectedDateOfDeath = patchedDayOfDeath;
-            return this;
-        }
-
-        void matches(final HsOfficePartnerEntity givenPartner) {
-
-            assertThat(givenPartner.getContact().getUuid()).isEqualTo(expectedContactUuid);
-            assertThat(givenPartner.getPerson().getUuid()).isEqualTo(expectedPersonUuid);
-            assertThat(givenPartner.getRegistrationOffice()).isEqualTo(expectedRegOffice);
-            assertThat(givenPartner.getRegistrationNumber()).isEqualTo(expectedRegNumber);
-            assertThat(givenPartner.getBirthday()).isEqualTo(expectedBirthday);
-            assertThat(givenPartner.getBirthName()).isEqualTo(expectedBirthName);
-            assertThat(givenPartner.getDateOfDeath()).isEqualTo(expectedDateOfDeath);
-
-        }
-
-    }
-
-    enum LocalDatePatches {
-        REAL_VALUE(LocalDate.now()),
-        NULL_VALUE(null);
-
-        final LocalDate value;
-
-        LocalDatePatches(final LocalDate patchedBirthday) {
-            value = patchedBirthday;
-        }
-    }
-
 }
diff --git a/src/test/java/net/hostsharing/hsadminng/hs/office/partner/PatchUnitTestBase.java b/src/test/java/net/hostsharing/hsadminng/hs/office/partner/PatchUnitTestBase.java
new file mode 100644
index 00000000..2ec6d0f9
--- /dev/null
+++ b/src/test/java/net/hostsharing/hsadminng/hs/office/partner/PatchUnitTestBase.java
@@ -0,0 +1,210 @@
+package net.hostsharing.hsadminng.hs.office.partner;
+
+import org.junit.jupiter.api.Named;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+import org.openapitools.jackson.nullable.JsonNullable;
+
+import java.util.NoSuchElementException;
+import java.util.UUID;
+import java.util.function.BiConsumer;
+import java.util.stream.Stream;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.catchThrowableOfType;
+import static org.assertj.core.api.Assumptions.assumeThat;
+
+public abstract class PatchUnitTestBase<R, E> {
+
+    @Test
+    void willPatchNoProperty() {
+        // given
+        final var givenEntity = newInitialEntity();
+        final var patchResource = newPatchResource();
+
+        // when
+        createPatcher(givenEntity).apply(patchResource);
+
+        // then
+        final var expectedEntity = newInitialEntity();
+        assertThat(givenEntity).usingRecursiveComparison().isEqualTo(expectedEntity);
+    }
+
+    @Test
+    void willPatchAllProperties() {
+        // given
+        final var givenEntity = newInitialEntity();
+        final var patchResource = newPatchResource();
+        testCases().forEach(testCase ->
+                testCase.resourceSetter.accept(patchResource, JsonNullable.of(testCase.givenPatchedValue))
+        );
+
+        // when
+        createPatcher(givenEntity).apply(patchResource);
+
+        // then
+        final var expectedEntity = newInitialEntity();
+        testCases().forEach(testCase ->
+                testCase.entitySetter.accept(expectedEntity, testCase.expectedPatchValue)
+        );
+        assertThat(givenEntity).usingRecursiveComparison().isEqualTo(expectedEntity);
+    }
+
+    @ParameterizedTest
+    @MethodSource("testCaseArguments")
+    void willPatchOnlyGivenProperty(final TestCase testCase) {
+
+        // given
+        final var givenEntity = newInitialEntity();
+        final var patchResource = newPatchResource();
+        testCase.resourceSetter.accept(patchResource, JsonNullable.of(testCase.givenPatchedValue));
+
+        // when
+        createPatcher(givenEntity).apply(patchResource);
+
+        // then
+        final var expectedEntity = newInitialEntity();
+        testCase.entitySetter.accept(expectedEntity, testCase.expectedPatchValue);
+        assertThat(givenEntity).usingRecursiveComparison().isEqualTo(expectedEntity);
+    }
+
+    @ParameterizedTest
+    @MethodSource("testCaseArguments")
+    void willThrowIfUUidCannotBeResolved(final TestCase testCase) {
+        assumeThat(testCase.resolvesUuid).isTrue();
+
+        // given
+        final var givenEntity = newInitialEntity();
+        final var patchResource = newPatchResource();
+        final var givenPatchValue = UUID.fromString("11111111-1111-1111-1111-111111111111");
+        testCase.resourceSetter.accept(patchResource, JsonNullable.of(givenPatchValue));
+
+        // when
+        final var exception = catchThrowableOfType(() -> {
+            createPatcher(givenEntity).apply(patchResource);
+        }, NoSuchElementException.class);
+
+        // then
+        assertThat(exception).isInstanceOf(NoSuchElementException.class)
+                .hasMessage("cannot find '" + testCase.name + "' uuid " + givenPatchValue);
+    }
+
+    @ParameterizedTest
+    @MethodSource("testCaseArguments")
+    void willPatchOnlyGivenPropertyToNull(final TestCase testCase) {
+        assumeThat(testCase.nullable).isTrue();
+
+        // given
+        final var givenEntity = newInitialEntity();
+        final var patchResource = newPatchResource();
+        testCase.resourceSetter.accept(patchResource, JsonNullable.of(null));
+
+        // when
+        createPatcher(givenEntity).apply(patchResource);
+
+        // then
+        final var expectedEntity = newInitialEntity();
+        testCase.entitySetter.accept(expectedEntity, null);
+        assertThat(givenEntity).usingRecursiveComparison().isEqualTo(expectedEntity);
+    }
+
+    @ParameterizedTest
+    @MethodSource("testCaseArguments")
+    void willThrowExceptionIfResourcePropertyIsNull(final TestCase testCase) {
+        assumeThat(testCase.nullable).isFalse();
+
+        // given
+        final var givenEntity = newInitialEntity();
+        final var patchResource = newPatchResource();
+        testCase.resourceSetter.accept(patchResource, JsonNullable.of(null));
+
+        // when
+        final var actualException = catchThrowableOfType(
+                () -> createPatcher(givenEntity).apply(patchResource),
+                IllegalArgumentException.class);
+
+        // then
+        assertThat(actualException).hasMessage("property '" + testCase.name + "' must not be null");
+        assertThat(givenEntity).usingRecursiveComparison().isEqualTo(newInitialEntity());
+    }
+
+    @ParameterizedTest
+    @MethodSource("testCaseArguments")
+    void willNotPatchIfGivenPropertyNotGiven(final TestCase testCase) {
+
+        // given
+        final var givenEntity = newInitialEntity();
+        final var patchResource = newPatchResource();
+        testCase.resourceSetter.accept(patchResource, null);
+
+        // when
+        createPatcher(givenEntity).apply(patchResource);
+
+        // then
+        final var expectedEntity = newInitialEntity();
+        assertThat(givenEntity).usingRecursiveComparison().isEqualTo(expectedEntity);
+    }
+
+    abstract E newInitialEntity();
+
+    abstract R newPatchResource();
+
+    abstract EntityPatch<R> createPatcher(final E entity);
+
+    abstract Stream<TestCase> testCases();
+
+    Stream<Arguments> testCaseArguments() {
+        return testCases().map(tc -> Arguments.of(Named.of(tc.name, tc)));
+    }
+
+    class TestCase {
+
+        private final String name;
+        public final Object givenPatchedValue;
+        private final BiConsumer<Object, JsonNullable<?>> resourceSetter;
+        private final BiConsumer<Object, Object> entitySetter;
+        private final Object expectedPatchValue;
+
+        private boolean nullable = true;
+        private boolean resolvesUuid = false;
+
+        <R, V, E> TestCase(
+                final String name,
+                final BiConsumer<R, JsonNullable<V>> resourceSetter,
+                final V givenPatchValue,
+                final BiConsumer<E, V> entitySetter
+        ) {
+            this.name = name;
+            this.resourceSetter = (BiConsumer<Object, JsonNullable<?>>) (BiConsumer) resourceSetter;
+            this.givenPatchedValue = givenPatchValue;
+            this.entitySetter = (BiConsumer<Object, Object>) entitySetter;
+            this.expectedPatchValue = givenPatchValue;
+        }
+
+        <R, V, E, S> TestCase(
+                final String name,
+                final BiConsumer<R, JsonNullable<V>> resourceSetter,
+                final V givenPatchValue,
+                final BiConsumer<E, S> entitySetter,
+                final S expectedPatchValue
+        ) {
+            this.name = name;
+            this.resourceSetter = (BiConsumer<Object, JsonNullable<?>>) (BiConsumer) resourceSetter;
+            this.givenPatchedValue = givenPatchValue;
+            this.entitySetter = (BiConsumer<Object, Object>) entitySetter;
+            this.expectedPatchValue = expectedPatchValue;
+        }
+
+        TestCase notNullable() {
+            nullable = false;
+            return this;
+        }
+
+        TestCase resolvesUuid() {
+            resolvesUuid = true;
+            return this;
+        }
+    }
+}