diff --git a/pom.xml b/pom.xml index 4b1e47aec..a60c8e7f9 100644 --- a/pom.xml +++ b/pom.xml @@ -145,6 +145,8 @@ event-sourcing data-transfer-object throttling + + unit-of-work partial-response eip-wire-tap eip-splitter diff --git a/unit-of-work/README.md b/unit-of-work/README.md new file mode 100644 index 000000000..b2fbde8ff --- /dev/null +++ b/unit-of-work/README.md @@ -0,0 +1,31 @@ +--- +layout: pattern +title: Unit Of Work +folder: unit-of-work +permalink: /patterns/unit-of-work/ + +categories: Architectural +tags: + - Java + - KISS + - YAGNI + - Difficulty-Beginner +--- + +## Intent +When a business transaction is completed, all the these updates are sent as one + big unit of work to be persisted in a database in one go so as to minimize database trips. + +![alt text](etc/unit-of-work.urm.png "unit-of-work") + +## Applicability +Use the Unit Of Work pattern when + +* To optimize the time taken for database transactions. +* To send changes to database as a unit of work which ensures atomicity of the transaction. +* To reduce number of database calls. + +## Credits + +* [Design Pattern - Unit Of Work Pattern](https://www.codeproject.com/Articles/581487/Unit-of-Work-Design-Pattern) +* [Unit Of Work](https://martinfowler.com/eaaCatalog/unitOfWork.html) diff --git a/unit-of-work/etc/unit-of-work.ucls b/unit-of-work/etc/unit-of-work.ucls new file mode 100644 index 000000000..98181f805 --- /dev/null +++ b/unit-of-work/etc/unit-of-work.ucls @@ -0,0 +1,68 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/unit-of-work/etc/unit-of-work.urm.png b/unit-of-work/etc/unit-of-work.urm.png new file mode 100644 index 000000000..bb192af54 Binary files /dev/null and b/unit-of-work/etc/unit-of-work.urm.png differ diff --git a/unit-of-work/etc/unit-of-work.urm.puml b/unit-of-work/etc/unit-of-work.urm.puml new file mode 100644 index 000000000..7767a2e32 --- /dev/null +++ b/unit-of-work/etc/unit-of-work.urm.puml @@ -0,0 +1,48 @@ +@startuml +package com.iluwatar.unitofwork { + class App { + + App() + + main(args : String[]) {static} + } + interface IUnitOfWork { + + DELETE : String {static} + + INSERT : String {static} + + MODIFY : String {static} + + commit() {abstract} + + registerDeleted(T) {abstract} + + registerModified(T) {abstract} + + registerNew(T) {abstract} + } + class Student { + - address : String + - id : Integer + - name : String + + Student(id : Integer, name : String, address : String) + + getAddress() : String + + getId() : Integer + + getName() : String + } + class StudentDatabase { + + StudentDatabase() + + delete(student : Student) + + insert(student : Student) + + modify(student : Student) + } + class StudentRepository { + - LOGGER : Logger {static} + - context : Map> + - studentDatabase : StudentDatabase + + StudentRepository(context : Map>, studentDatabase : StudentDatabase) + + commit() + - commitDelete() + - commitInsert() + - commitModify() + - register(student : Student, operation : String) + + registerDeleted(student : Student) + + registerModified(student : Student) + + registerNew(student : Student) + } +} +StudentRepository --> "-studentDatabase" StudentDatabase +StudentRepository ..|> IUnitOfWork +@enduml \ No newline at end of file diff --git a/unit-of-work/pom.xml b/unit-of-work/pom.xml new file mode 100644 index 000000000..0d7fbf5a2 --- /dev/null +++ b/unit-of-work/pom.xml @@ -0,0 +1,25 @@ + + + + java-design-patterns + com.iluwatar + 1.18.0-SNAPSHOT + + 4.0.0 + + unit-of-work + + + junit + junit + + + org.mockito + mockito-core + + + + + \ No newline at end of file diff --git a/unit-of-work/src/main/java/com/iluwatar/unitofwork/App.java b/unit-of-work/src/main/java/com/iluwatar/unitofwork/App.java new file mode 100644 index 000000000..9b4b2f15c --- /dev/null +++ b/unit-of-work/src/main/java/com/iluwatar/unitofwork/App.java @@ -0,0 +1,52 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2014-2017 Piyush Chaudhari + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.iluwatar.unitofwork; + +import java.util.HashMap; +import java.util.List; + +/** + * {@link App} Application for managing student data. + */ +public class App { + /** + * + * @param args no argument sent + */ + public static void main(String[] args) { + Student ram = new Student(1, "Ram", "Street 9, Cupertino"); + Student shyam = new Student(2, "Shyam", "Z bridge, Pune"); + Student gopi = new Student(3, "Gopi", "Street 10, Mumbai"); + + HashMap> context = new HashMap<>(); + StudentDatabase studentDatabase = new StudentDatabase(); + StudentRepository studentRepository = new StudentRepository(context, studentDatabase); + + studentRepository.registerNew(ram); + studentRepository.registerModified(shyam); + studentRepository.registerDeleted(gopi); + studentRepository.commit(); + } +} diff --git a/unit-of-work/src/main/java/com/iluwatar/unitofwork/IUnitOfWork.java b/unit-of-work/src/main/java/com/iluwatar/unitofwork/IUnitOfWork.java new file mode 100644 index 000000000..e0b453498 --- /dev/null +++ b/unit-of-work/src/main/java/com/iluwatar/unitofwork/IUnitOfWork.java @@ -0,0 +1,55 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2014-2017 Piyush Chaudhari + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.iluwatar.unitofwork; + +/** + * @param Any generic entity + */ +public interface IUnitOfWork { + String INSERT = "INSERT"; + String DELETE = "DELETE"; + String MODIFY = "MODIFY"; + + /** + * Any register new operation occurring on UnitOfWork is only going to be performed on commit. + */ + void registerNew(T entity); + + /** + * Any register modify operation occurring on UnitOfWork is only going to be performed on commit. + */ + void registerModified(T entity); + + /** + * Any register delete operation occurring on UnitOfWork is only going to be performed on commit. + */ + void registerDeleted(T entity); + + /*** + * All UnitOfWork operations batched together executed in commit only. + */ + void commit(); + +} \ No newline at end of file diff --git a/unit-of-work/src/main/java/com/iluwatar/unitofwork/Student.java b/unit-of-work/src/main/java/com/iluwatar/unitofwork/Student.java new file mode 100644 index 000000000..5a57ccdde --- /dev/null +++ b/unit-of-work/src/main/java/com/iluwatar/unitofwork/Student.java @@ -0,0 +1,57 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2014-2017 Piyush Chaudhari + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.iluwatar.unitofwork; + +/** + * {@link Student} is an entity. + */ +public class Student { + private final Integer id; + private final String name; + private final String address; + + /** + * @param id student unique id + * @param name name of student + * @param address address of student + */ + public Student(Integer id, String name, String address) { + this.id = id; + this.name = name; + this.address = address; + } + + public String getName() { + return name; + } + + public Integer getId() { + return id; + } + + public String getAddress() { + return address; + } +} diff --git a/unit-of-work/src/main/java/com/iluwatar/unitofwork/StudentDatabase.java b/unit-of-work/src/main/java/com/iluwatar/unitofwork/StudentDatabase.java new file mode 100644 index 000000000..6b0e85517 --- /dev/null +++ b/unit-of-work/src/main/java/com/iluwatar/unitofwork/StudentDatabase.java @@ -0,0 +1,43 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2014-2017 Piyush Chaudhari + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.iluwatar.unitofwork; + +/** + * Act as Database for student records. + */ +public class StudentDatabase { + + public void insert(Student student) { + //Some insert logic to DB + } + + public void modify(Student student) { + //Some modify logic to DB + } + + public void delete(Student student) { + //Some delete logic to DB + } +} diff --git a/unit-of-work/src/main/java/com/iluwatar/unitofwork/StudentRepository.java b/unit-of-work/src/main/java/com/iluwatar/unitofwork/StudentRepository.java new file mode 100644 index 000000000..ff1136620 --- /dev/null +++ b/unit-of-work/src/main/java/com/iluwatar/unitofwork/StudentRepository.java @@ -0,0 +1,126 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2014-2017 Piyush Chaudhari + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.iluwatar.unitofwork; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +/** + * {@link StudentRepository} Student database repository. + * supports unit of work for student data. + */ +public class StudentRepository implements IUnitOfWork { + private static final Logger LOGGER = LoggerFactory.getLogger(StudentRepository.class); + + private Map> context; + private StudentDatabase studentDatabase; + + /** + * @param context set of operations to be perform during commit. + * @param studentDatabase Database for student records. + */ + public StudentRepository(Map> context, StudentDatabase studentDatabase) { + this.context = context; + this.studentDatabase = studentDatabase; + } + + @Override + public void registerNew(Student student) { + LOGGER.info("Registering {} for insert in context.", student.getName()); + register(student, IUnitOfWork.INSERT); + } + + @Override + public void registerModified(Student student) { + LOGGER.info("Registering {} for modify in context.", student.getName()); + register(student, IUnitOfWork.MODIFY); + + } + + @Override + public void registerDeleted(Student student) { + LOGGER.info("Registering {} for delete in context.", student.getName()); + register(student, IUnitOfWork.DELETE); + } + + private void register(Student student, String operation) { + List studentsToOperate = context.get(operation); + if (studentsToOperate == null) { + studentsToOperate = new ArrayList<>(); + } + studentsToOperate.add(student); + context.put(operation, studentsToOperate); + } + + /** + * All UnitOfWork operations are batched and executed together on commit only. + */ + @Override + public void commit() { + if (context == null || context.size() == 0) { + return; + } + LOGGER.info("Commit started"); + if (context.containsKey(IUnitOfWork.INSERT)) { + commitInsert(); + } + + if (context.containsKey(IUnitOfWork.MODIFY)) { + commitModify(); + } + if (context.containsKey(IUnitOfWork.DELETE)) { + commitDelete(); + } + LOGGER.info("Commit finished."); + } + + private void commitInsert() { + List studentsToBeInserted = context.get(IUnitOfWork.INSERT); + for (Student student : studentsToBeInserted) { + LOGGER.info("Saving {} to database.", student.getName()); + studentDatabase.insert(student); + } + } + + private void commitModify() { + List modifiedStudents = context.get(IUnitOfWork.MODIFY); + for (Student student : modifiedStudents) { + LOGGER.info("Modifying {} to database.", student.getName()); + studentDatabase.modify(student); + } + } + + private void commitDelete() { + List deletedStudents = context.get(IUnitOfWork.DELETE); + for (Student student : deletedStudents) { + LOGGER.info("Deleting {} to database.", student.getName()); + studentDatabase.delete(student); + } + } +} diff --git a/unit-of-work/src/test/java/com/iluwatar/unitofwork/AppTest.java b/unit-of-work/src/test/java/com/iluwatar/unitofwork/AppTest.java new file mode 100644 index 000000000..942db781f --- /dev/null +++ b/unit-of-work/src/test/java/com/iluwatar/unitofwork/AppTest.java @@ -0,0 +1,40 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2014-2017 Piyush Chaudhari + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.iluwatar.unitofwork; + +import org.junit.Test; + +import java.io.IOException; + +/** + * AppTest + */ +public class AppTest { + @Test + public void test() throws IOException { + String[] args = {}; + App.main(args); + } +} diff --git a/unit-of-work/src/test/java/com/iluwatar/unitofwork/StudentRepositoryTest.java b/unit-of-work/src/test/java/com/iluwatar/unitofwork/StudentRepositoryTest.java new file mode 100644 index 000000000..ee63442a5 --- /dev/null +++ b/unit-of-work/src/test/java/com/iluwatar/unitofwork/StudentRepositoryTest.java @@ -0,0 +1,147 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2014-2017 Piyush Chaudhari + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.iluwatar.unitofwork; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; + +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.*; + +/** + * tests {@link StudentRepository} + */ +@RunWith(MockitoJUnitRunner.class) +public class StudentRepositoryTest { + private final Student student1 = new Student(1, "Ram", "street 9, cupertino"); + private final Student student2 = new Student(1, "Sham", "Z bridge, pune"); + + private Map> context; + @Mock + private StudentDatabase studentDatabase; + private StudentRepository studentRepository; + + @Before + public void setUp() throws Exception { + context = new HashMap<>(); + studentRepository = new StudentRepository(context, studentDatabase); + } + + @Test + public void shouldSaveNewStudentWithoutWritingToDb() throws Exception { + studentRepository.registerNew(student1); + studentRepository.registerNew(student2); + + assertEquals(2, context.get(IUnitOfWork.INSERT).size()); + verifyNoMoreInteractions(studentDatabase); + } + + @Test + public void shouldSaveDeletedStudentWithoutWritingToDb() throws Exception { + studentRepository.registerDeleted(student1); + studentRepository.registerDeleted(student2); + + assertEquals(2, context.get(IUnitOfWork.DELETE).size()); + verifyNoMoreInteractions(studentDatabase); + } + + @Test + public void shouldSaveModifiedStudentWithoutWritingToDb() throws Exception { + studentRepository.registerModified(student1); + studentRepository.registerModified(student2); + + assertEquals(2, context.get(IUnitOfWork.MODIFY).size()); + verifyNoMoreInteractions(studentDatabase); + } + + @Test + public void shouldSaveAllLocalChangesToDb() throws Exception { + context.put(IUnitOfWork.INSERT, Collections.singletonList(student1)); + context.put(IUnitOfWork.MODIFY, Collections.singletonList(student1)); + context.put(IUnitOfWork.DELETE, Collections.singletonList(student1)); + + studentRepository.commit(); + + verify(studentDatabase, times(1)).insert(student1); + verify(studentDatabase, times(1)).modify(student1); + verify(studentDatabase, times(1)).delete(student1); + } + + @Test + public void shouldNotWriteToDbIfContextIsNull() throws Exception { + StudentRepository studentRepository = new StudentRepository(null, studentDatabase); + + studentRepository.commit(); + + verifyNoMoreInteractions(studentDatabase); + } + + @Test + public void shouldNotWriteToDbIfNothingToCommit() throws Exception { + StudentRepository studentRepository = new StudentRepository(new HashMap<>(), studentDatabase); + + studentRepository.commit(); + + verifyZeroInteractions(studentDatabase); + } + + @Test + public void shouldNotInsertToDbIfNoRegisteredStudentsToBeCommitted() throws Exception { + context.put(IUnitOfWork.MODIFY, Collections.singletonList(student1)); + context.put(IUnitOfWork.DELETE, Collections.singletonList(student1)); + + studentRepository.commit(); + + verify(studentDatabase, never()).insert(student1); + } + + @Test + public void shouldNotModifyToDbIfNotRegisteredStudentsToBeCommitted() throws Exception { + context.put(IUnitOfWork.INSERT, Collections.singletonList(student1)); + context.put(IUnitOfWork.DELETE, Collections.singletonList(student1)); + + studentRepository.commit(); + + verify(studentDatabase, never()).modify(student1); + } + + @Test + public void shouldNotDeleteFromDbIfNotRegisteredStudentsToBeCommitted() throws Exception { + context.put(IUnitOfWork.INSERT, Collections.singletonList(student1)); + context.put(IUnitOfWork.MODIFY, Collections.singletonList(student1)); + + studentRepository.commit(); + + verify(studentDatabase, never()).delete(student1); + } +} \ No newline at end of file