From 35abe7093387dd0b3218ac0bb9047a7140a0e82c Mon Sep 17 00:00:00 2001 From: JonesWVU Date: Mon, 3 Jan 2022 18:49:33 -0500 Subject: [PATCH] Further migrating to DTOs and updating tests --- .../contacts/ContactsApplication.java | 2 - .../controller/ContactController.java | 77 +++++------ .../singlestone/contacts/model/Address.java | 10 -- .../contacts/model/CallListEntry.java | 10 -- .../singlestone/contacts/model/Contact.java | 35 ++--- .../com/singlestone/contacts/model/Name.java | 9 -- .../com/singlestone/contacts/model/Phone.java | 7 +- .../contacts/model/dto/CallListDTO.java | 16 ++- .../contacts/model/dto/ContactDTO.java | 39 +++++- .../contacts/model/dto/PhoneDTO.java | 19 ++- .../contacts/repository/PhoneRepository.java | 5 +- .../contacts/service/ContactService.java | 74 ++++++++--- src/main/resources/application.properties | 15 ++- src/main/resources/data.sql | 14 +- .../controller/ContactControllerTest.java | 125 ++++++++++++++++++ .../contacts/resources/application.properties | 17 +++ .../singlestone/contacts/resources/data.sql | 25 ++++ .../contacts/service/ContactServiceTest.java | 116 ++++++++++++++++ 18 files changed, 480 insertions(+), 135 deletions(-) delete mode 100644 src/main/java/com/singlestone/contacts/model/CallListEntry.java create mode 100644 src/test/java/com/singlestone/contacts/controller/ContactControllerTest.java create mode 100644 src/test/java/com/singlestone/contacts/resources/application.properties create mode 100644 src/test/java/com/singlestone/contacts/resources/data.sql create mode 100644 src/test/java/com/singlestone/contacts/service/ContactServiceTest.java diff --git a/src/main/java/com/singlestone/contacts/ContactsApplication.java b/src/main/java/com/singlestone/contacts/ContactsApplication.java index b0ca9eb..457a2a4 100644 --- a/src/main/java/com/singlestone/contacts/ContactsApplication.java +++ b/src/main/java/com/singlestone/contacts/ContactsApplication.java @@ -5,9 +5,7 @@ import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class ContactsApplication { - public static void main(String[] args) { SpringApplication.run(ContactsApplication.class, args); } - } diff --git a/src/main/java/com/singlestone/contacts/controller/ContactController.java b/src/main/java/com/singlestone/contacts/controller/ContactController.java index 4006c96..ba68793 100644 --- a/src/main/java/com/singlestone/contacts/controller/ContactController.java +++ b/src/main/java/com/singlestone/contacts/controller/ContactController.java @@ -1,82 +1,83 @@ package com.singlestone.contacts.controller; -import com.singlestone.contacts.model.CallListEntry; -import com.singlestone.contacts.model.Contact; -import com.singlestone.contacts.model.Phone; +import com.singlestone.contacts.model.dto.CallListDTO; import com.singlestone.contacts.model.dto.ContactDTO; -import com.singlestone.contacts.repository.ContactRepository; -import com.singlestone.contacts.repository.PhoneRepository; import com.singlestone.contacts.service.ContactService; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.data.domain.Sort; -import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.*; -import org.springframework.web.server.ResponseStatusException; + +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; import java.util.List; -import java.util.Optional; @RestController -// @RequestMapping("/api/v1") +@RequestMapping("/api/v1") public class ContactController { @Autowired private ContactService contactService; - @Autowired - private PhoneRepository phoneRepository; - //Get All Contacts @GetMapping("/contacts") - public List getAllContacts() { - return contactService.getAllContacts(); + public ResponseEntity> getAllContacts() { + List allContacts = contactService.getAllContacts(); + if (allContacts.isEmpty()) { + return new ResponseEntity<>(HttpStatus.NO_CONTENT); + } + return new ResponseEntity<>(allContacts, HttpStatus.OK); } //Create a new contact @PostMapping("/contacts") - public void newContact(@RequestBody Contact newContact) + public ResponseEntity createContact(@RequestBody ContactDTO newContact) { - contactRepository.save(newContact); + ContactDTO createdContact = contactService.createContact(newContact); + if (createdContact == null) { + return new ResponseEntity<>(HttpStatus.BAD_REQUEST); + } + return new ResponseEntity<>(HttpStatus.CREATED); } //Update an existing contact @PutMapping("/contacts/{id}") - public void updateContact(@PathVariable long id, @RequestBody Contact newContact) + public ResponseEntity updateContact(@PathVariable long id, @RequestBody ContactDTO newContactInfo) { - Optional contact = contactRepository.findById(id); - if (contact.isEmpty()) { - throw new ResponseStatusException(HttpStatus.NOT_FOUND); + ContactDTO updatedContact = contactService.updateContact(id, newContactInfo); + if (updatedContact == null) { + return new ResponseEntity<>(HttpStatus.NOT_FOUND); } - Contact updatedContact = new Contact(id, newContact); - contactRepository.save(updatedContact); + return new ResponseEntity<>(HttpStatus.OK); } //Get a single contact @GetMapping("/contacts/{id}") - public Contact getContact(@PathVariable long id) { - Optional contact = contactRepository.findById(id); - if (contact.isEmpty()) { - throw new ResponseStatusException(HttpStatus.NOT_FOUND, "Unable to find specified contact ID: " + id); + public ResponseEntity getContact(@PathVariable long id) { + ContactDTO contact = contactService.getContact(id); + if (contact == null) { + return new ResponseEntity<>(HttpStatus.NOT_FOUND); } - return contact.get(); + return new ResponseEntity<>(contact, HttpStatus.OK); } //Delete a contact @DeleteMapping("/contacts/{id}") - public void deleteContact(@PathVariable long id) { - Optional contact = contactRepository.findById(id); - if (contact.isEmpty()) { - throw new ResponseStatusException(HttpStatus.NOT_FOUND, "Unable to find specified contact ID: " + id); + public ResponseEntity deleteContact(@PathVariable long id) { + ContactDTO contact = contactService.deleteContact(id); + if (contact == null) { + return new ResponseEntity<>(HttpStatus.NOT_FOUND); } - contactRepository.deleteById(id); + return new ResponseEntity<>(HttpStatus.NO_CONTENT); } - //Get a single contact + //Get a list of contacts with home phone numbers @GetMapping("/contacts/call-list") - public List getCallList() { - Sort sortByLast = Sort.by("contact.name.last").ascending(); - Sort sortByFirst = Sort.by("contact.name.first").ascending(); - return phoneRepository.findByType(Phone.Type.home, sortByLast.and(sortByFirst)); + public ResponseEntity> getCallList() { + List callList = contactService.getCallList(); + if (callList.isEmpty()) { + return new ResponseEntity<>(HttpStatus.NO_CONTENT); + } + return new ResponseEntity<>(callList, HttpStatus.OK); } } diff --git a/src/main/java/com/singlestone/contacts/model/Address.java b/src/main/java/com/singlestone/contacts/model/Address.java index cc1e306..f57b23d 100644 --- a/src/main/java/com/singlestone/contacts/model/Address.java +++ b/src/main/java/com/singlestone/contacts/model/Address.java @@ -16,16 +16,6 @@ public class Address { @Column(name = "zip") private String zip; - public Address() { - } - - public Address(String street, String city, String state, String zip) { - this.street = street; - this.city = city; - this.state = state; - this.zip = zip; - } - public String getStreet() { return street; } diff --git a/src/main/java/com/singlestone/contacts/model/CallListEntry.java b/src/main/java/com/singlestone/contacts/model/CallListEntry.java deleted file mode 100644 index 71a09a3..0000000 --- a/src/main/java/com/singlestone/contacts/model/CallListEntry.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.singlestone.contacts.model; - -import org.springframework.beans.factory.annotation.Value; - -public interface CallListEntry { - @Value("#{target.getContact().getName()}") - Name getName(); - @Value("#{target.getNumber()}") - String getPhone(); -} diff --git a/src/main/java/com/singlestone/contacts/model/Contact.java b/src/main/java/com/singlestone/contacts/model/Contact.java index c337b3b..583d8ce 100644 --- a/src/main/java/com/singlestone/contacts/model/Contact.java +++ b/src/main/java/com/singlestone/contacts/model/Contact.java @@ -3,7 +3,9 @@ package com.singlestone.contacts.model; import javax.persistence.*; import javax.validation.constraints.Email; import java.util.List; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import java.util.stream.Collectors; + +import com.singlestone.contacts.model.dto.ContactDTO; @Entity @Table(name = "contacts") @@ -19,31 +21,34 @@ public class Contact { @Embedded private Address address; - @OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true) + @OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL, orphanRemoval = true) @JoinColumn(name = "contact_id", referencedColumnName = "id") - @JsonIgnoreProperties({"id", "contact"}) private List phone; @Email(message = "Email address is not in a valid format") @Column(name = "email") private String email; - public Contact() { + public Contact() {} + + public Contact(long id, Contact contact) { + this.id = id; + name = contact.getName(); + address = contact.getAddress(); + phone = contact.getPhone(); + email = contact.getEmail(); } - public Contact(Long id, Contact contact) { - setId(id); - setName(contact.getName()); - setAddress(contact.getAddress()); - setPhone(contact.getPhone()); - setEmail(contact.getEmail()); + public Contact(ContactDTO contact) { + name = contact.getName(); + address = contact.getAddress(); + setPhone(contact.getPhone().stream().map(dto -> new Phone(dto.getNumber(), dto.getType())).collect(Collectors.toList())); + email = contact.getEmail(); } - public Contact(Name name, Address address, List phone, String email) { - this.name = name; - this.address = address; - this.phone = phone; - this.email = email; + public Contact(long id, ContactDTO contact) { + this(contact); + setId(id); } public Long getId() { diff --git a/src/main/java/com/singlestone/contacts/model/Name.java b/src/main/java/com/singlestone/contacts/model/Name.java index 9cc46ce..d41ae09 100644 --- a/src/main/java/com/singlestone/contacts/model/Name.java +++ b/src/main/java/com/singlestone/contacts/model/Name.java @@ -13,15 +13,6 @@ public class Name { @Column(name = "last") private String last; - public Name() { - } - - public Name(String first, String middle, String last) { - this.first = first; - this.middle = middle; - this.last = last; - } - public String getFirst() { return first; } diff --git a/src/main/java/com/singlestone/contacts/model/Phone.java b/src/main/java/com/singlestone/contacts/model/Phone.java index 1095df2..07d6d99 100644 --- a/src/main/java/com/singlestone/contacts/model/Phone.java +++ b/src/main/java/com/singlestone/contacts/model/Phone.java @@ -20,12 +20,11 @@ public class Phone { @ManyToOne(fetch = FetchType.LAZY) private Contact contact; - public Phone() { - } + public Phone() {} - public Phone(String number, Type type) { + public Phone(String number, String type) { this.number = number; - this.type = type; + this.type = Type.valueOf(type.toUpperCase()); } public Long getId() { diff --git a/src/main/java/com/singlestone/contacts/model/dto/CallListDTO.java b/src/main/java/com/singlestone/contacts/model/dto/CallListDTO.java index 2ea6ddf..5667cbf 100644 --- a/src/main/java/com/singlestone/contacts/model/dto/CallListDTO.java +++ b/src/main/java/com/singlestone/contacts/model/dto/CallListDTO.java @@ -1,11 +1,23 @@ package com.singlestone.contacts.model.dto; -import com.singlestone.contacts.model.Address; import com.singlestone.contacts.model.Name; +import com.singlestone.contacts.model.Phone; public class CallListDTO { private Name name; private String phone; - + + public CallListDTO(Phone phone) { + name = phone.getContact().getName(); + this.phone = phone.getNumber(); + } + + public Name getName() { + return name; + } + + public String getPhone() { + return phone; + } } diff --git a/src/main/java/com/singlestone/contacts/model/dto/ContactDTO.java b/src/main/java/com/singlestone/contacts/model/dto/ContactDTO.java index fefe6eb..069c9ad 100644 --- a/src/main/java/com/singlestone/contacts/model/dto/ContactDTO.java +++ b/src/main/java/com/singlestone/contacts/model/dto/ContactDTO.java @@ -1,18 +1,39 @@ package com.singlestone.contacts.model.dto; +import java.util.ArrayList; import java.util.List; +import java.util.stream.Collectors; import com.singlestone.contacts.model.Address; +import com.singlestone.contacts.model.Contact; import com.singlestone.contacts.model.Name; -import com.singlestone.contacts.model.Phone; public class ContactDTO { + private long id; private Name name; private Address address; - private List phone; + private List phone; private String email; + public ContactDTO() {} + + public ContactDTO(Contact contact) { + id = contact.getId(); + name = contact.getName(); + address = contact.getAddress(); + email = contact.getEmail(); + setPhone(contact.getPhone().stream().map(contactPhone -> new PhoneDTO(contactPhone.getNumber(), contactPhone.getType())).collect(Collectors.toList())); + } + + public void setId(long id) { + this.id = id; + } + + public long getId() { + return id; + } + public void setName(Name name) { this.name = name; } @@ -29,14 +50,18 @@ public class ContactDTO { return address; } - public void setPhone(List phone) { - this.phone.clear(); - for (Phone p : phone) { - this.phone.add(p.getNumber()); + public void setPhone(List phone) { + if (this.phone != null) { + this.phone.clear(); + } else { + this.phone = new ArrayList<>(); + } + for (PhoneDTO p : phone) { + this.phone.add(p); } } - public List getPhone() { + public List getPhone() { return phone; } diff --git a/src/main/java/com/singlestone/contacts/model/dto/PhoneDTO.java b/src/main/java/com/singlestone/contacts/model/dto/PhoneDTO.java index 01dd5ad..21962cd 100644 --- a/src/main/java/com/singlestone/contacts/model/dto/PhoneDTO.java +++ b/src/main/java/com/singlestone/contacts/model/dto/PhoneDTO.java @@ -1,6 +1,23 @@ package com.singlestone.contacts.model.dto; +import com.singlestone.contacts.model.Phone.Type; + public class PhoneDTO { private String number; - private Type type; + private String type; + + public PhoneDTO() {} + + public PhoneDTO(String number, Type type) { + this.number = number; + this.type = type.name().toLowerCase(); + } + + public String getNumber() { + return number; + } + + public String getType() { + return type; + } } diff --git a/src/main/java/com/singlestone/contacts/repository/PhoneRepository.java b/src/main/java/com/singlestone/contacts/repository/PhoneRepository.java index d8a7989..b844238 100644 --- a/src/main/java/com/singlestone/contacts/repository/PhoneRepository.java +++ b/src/main/java/com/singlestone/contacts/repository/PhoneRepository.java @@ -6,10 +6,9 @@ import org.springframework.stereotype.Repository; import java.util.List; -import com.singlestone.contacts.model.CallListEntry; import com.singlestone.contacts.model.Phone; @Repository public interface PhoneRepository extends JpaRepository { - List findByType(Phone.Type type, Sort sortBy); -} \ No newline at end of file + List findByType(Phone.Type type, Sort sortBy); +} diff --git a/src/main/java/com/singlestone/contacts/service/ContactService.java b/src/main/java/com/singlestone/contacts/service/ContactService.java index 13cb690..63d887f 100644 --- a/src/main/java/com/singlestone/contacts/service/ContactService.java +++ b/src/main/java/com/singlestone/contacts/service/ContactService.java @@ -1,17 +1,19 @@ package com.singlestone.contacts.service; import java.util.List; +import java.util.Optional; import java.util.stream.Collectors; import com.singlestone.contacts.model.Contact; import com.singlestone.contacts.model.Phone; +import com.singlestone.contacts.model.dto.CallListDTO; import com.singlestone.contacts.model.dto.ContactDTO; import com.singlestone.contacts.repository.ContactRepository; import com.singlestone.contacts.repository.PhoneRepository; -import org.modelmapper.ModelMapper; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import org.springframework.data.domain.Sort; @Service public class ContactService { @@ -22,34 +24,64 @@ public class ContactService { @Autowired private PhoneRepository phoneRepository; - @Autowired - private ModelMapper modelMapper; + public ContactDTO createContact(ContactDTO newContact) { + try { + Contact contact = new Contact(newContact); + contactRepository.save(contact); + return new ContactDTO(contact); + } catch (IllegalArgumentException e) { + return null; + } + } public List getAllContacts() { - List contacts = contactRepository.findAll(); - return contacts.stream().map(this::convertToDTO).collect(Collectors.toList()); + return contactRepository.findAll().stream().map(ContactDTO::new).collect(Collectors.toList()); } - public void newContact(ContactDTO newContact) { - Contact contact = new Contact(); + public ContactDTO getContact(long id) { + Optional contact = contactRepository.findById(id); + + if (contact.isEmpty()) { + return null; + } + return new ContactDTO(contact.get()); + } + + public ContactDTO updateContact(long id, ContactDTO newContact) + { + Optional contact = contactRepository.findById(id); + + if (contact.isEmpty()) { + return null; + } + try { + Contact updatedContact = new Contact(id, newContact); + contactRepository.save(updatedContact); + return new ContactDTO(updatedContact); + } catch (Exception e) { + return null; + } } - private ContactDTO convertToDTO(Contact contact) { - ContactDTO dto = new ContactDTO(); - dto.setName(contact.getName()); - dto.setAddress(contact.getAddress()); - dto.setEmail(contact.getEmail()); - dto.setPhone(contact.getPhone()); - return dto; + public ContactDTO deleteContact(long id) { + Optional contact = contactRepository.findById(id); + if (contact.isEmpty()) { + return null; + } + try { + contactRepository.deleteById(id); + return new ContactDTO(contact.get()); + } catch (Exception e) { + return null; + } } - private Contact convertToEntity(ContactDTO contactDTO) { - Contact contact = new Contact(); - contact.setName(contactDTO.getName()); - contact.setAddress(contactDTO.getAddress()); - contact.setEmail(contactDTO.getEmail()); - contact.setPhone(contactDTO.getPhone().stream().map(phone -> new Phone(phone)).collect(Collectors.toList())); - return contact; + public List getCallList() { + Sort sortByLast = Sort.by("contact.name.last").ascending(); + Sort sortByFirst = Sort.by("contact.name.first").ascending(); + + return phoneRepository.findByType(Phone.Type.HOME, sortByLast.and(sortByFirst)) + .stream().map(CallListDTO::new).collect(Collectors.toList()); } } diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 602ede4..138c2fd 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -1,14 +1,17 @@ - -#Enable H2 console +# ---Comments without preceeding '---' are settings to enable for development +# ---Enable H2 console spring.h2.console.enabled=true -#Turn Statistics on +# ---Turn Statistics on spring.jpa.properties.hibernate.generate_statistics=true logging.level.org.hibernate.stat=debug -# Show all queries +# ---Show queries spring.jpa.show-sql=true +# ---In memory DB spring.datasource.url=jdbc:h2:mem:contactsdb spring.data.jpa.repositories.bootstrap-mode=default spring.jpa.properties.hibernate.format_sql=true +# ---Initialize Hibernate before loading from data.sql spring.jpa.defer-datasource-initialization=true -logging.level.org.hibernate.type=trace -server.error.include-message=always +logging.level.org.hibernate.type=debug +# ---For development only +# server.error.include-message=always diff --git a/src/main/resources/data.sql b/src/main/resources/data.sql index c6d30df..1e8ebdb 100644 --- a/src/main/resources/data.sql +++ b/src/main/resources/data.sql @@ -10,16 +10,16 @@ values('street4', 'city4', 'state4', 'zip4', 'e4@mail.com', 'a', 'a', 'b'); -- Phones insert into PHONES (number, type, contact_id) -values('111-111-1111', 'home', 1); +values('111-111-1111', 'HOME', 1); insert into PHONES (number, type, contact_id) -values('222-222-2222', 'work', 1); +values('222-222-2222', 'WORK', 1); insert into PHONES (number, type, contact_id) -values('333-333-3333', 'work', 2); +values('333-333-3333', 'WORK', 2); insert into PHONES (number, type, contact_id) -values('444-444-4444', 'home', 2); +values('444-444-4444', 'HOME', 2); insert into PHONES (number, type, contact_id) -values('555-555-5555', 'mobile', 3); +values('555-555-5555', 'MOBILE', 3); insert into PHONES (number, type, contact_id) -values('777-777-7777', 'work', 4); +values('777-777-7777', 'WORK', 4); insert into PHONES (number, type, contact_id) -values('888-888-8888', 'home', 4); +values('888-888-8888', 'HOME', 4); diff --git a/src/test/java/com/singlestone/contacts/controller/ContactControllerTest.java b/src/test/java/com/singlestone/contacts/controller/ContactControllerTest.java new file mode 100644 index 0000000..457cae7 --- /dev/null +++ b/src/test/java/com/singlestone/contacts/controller/ContactControllerTest.java @@ -0,0 +1,125 @@ +package com.singlestone.contacts.controller; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import java.util.ArrayList; +import java.util.List; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.singlestone.contacts.model.Address; +import com.singlestone.contacts.model.Name; +import com.singlestone.contacts.model.Phone.Type; +import com.singlestone.contacts.model.dto.ContactDTO; +import com.singlestone.contacts.model.dto.PhoneDTO; +import com.singlestone.contacts.service.ContactService; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.MediaType; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; + +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +@ExtendWith(MockitoExtension.class) +public class ContactControllerTest { + + @Mock + private ContactService contactService; + + @InjectMocks + private ContactController contactController; + + @Autowired + private MockMvc mockMvc; + + private ContactDTO createTestContactDTO() { + ContactDTO testContactDTO = new ContactDTO(); + + Name name = new Name(); + name.setFirst("first"); + name.setMiddle("middle"); + name.setLast("last"); + testContactDTO.setName(name); + + Address address = new Address(); + address.setStreet("street"); + address.setCity("city"); + address.setState("state"); + address.setZip("zip"); + + List phones = new ArrayList<>(); + phones.add(new PhoneDTO("111-111-1111", Type.HOME)); + + testContactDTO.setPhone(phones); + testContactDTO.setEmail("e@mail.com"); + + return testContactDTO; + } + + @BeforeEach + public void setup(){ + mockMvc = MockMvcBuilders.standaloneSetup(contactController).build(); + } + + @Test + void testCreateContact() throws Exception { + ContactDTO contactToCreate = createTestContactDTO(); + when(contactService.createContact(any())).thenReturn(contactToCreate); + mockMvc.perform(post("/api/v1/contacts"). + contentType(MediaType.APPLICATION_JSON). + content(asJsonString(contactToCreate))). + andExpect(status().isCreated()); + verify(contactService, times(1)).createContact(any()); + } + + @Test + void testGetAllContacts() throws Exception { + ContactDTO contactToCreate = createTestContactDTO(); + List contacts = new ArrayList<>(); + contacts.add(contactToCreate); + when(contactService.getAllContacts()).thenReturn(contacts); + mockMvc.perform(get("/api/v1/contacts"). + accept(MediaType.APPLICATION_JSON). + content("")). + andExpect(status().isOk()); + verify(contactService, times(1)).getAllContacts(); + } + + @Test + void testGetContact() { + + } + + @Test + void testUpdateContact() { + + } + + @Test + void testDeleteContact() { + + } + + @Test + void testGetCallList() { + + } + + public static String asJsonString(final Object obj){ + try{ + return new ObjectMapper().writeValueAsString(obj); + }catch (Exception e){ + throw new RuntimeException(e); + } + } +} diff --git a/src/test/java/com/singlestone/contacts/resources/application.properties b/src/test/java/com/singlestone/contacts/resources/application.properties new file mode 100644 index 0000000..138c2fd --- /dev/null +++ b/src/test/java/com/singlestone/contacts/resources/application.properties @@ -0,0 +1,17 @@ +# ---Comments without preceeding '---' are settings to enable for development +# ---Enable H2 console +spring.h2.console.enabled=true +# ---Turn Statistics on +spring.jpa.properties.hibernate.generate_statistics=true +logging.level.org.hibernate.stat=debug +# ---Show queries +spring.jpa.show-sql=true +# ---In memory DB +spring.datasource.url=jdbc:h2:mem:contactsdb +spring.data.jpa.repositories.bootstrap-mode=default +spring.jpa.properties.hibernate.format_sql=true +# ---Initialize Hibernate before loading from data.sql +spring.jpa.defer-datasource-initialization=true +logging.level.org.hibernate.type=debug +# ---For development only +# server.error.include-message=always diff --git a/src/test/java/com/singlestone/contacts/resources/data.sql b/src/test/java/com/singlestone/contacts/resources/data.sql new file mode 100644 index 0000000..1e8ebdb --- /dev/null +++ b/src/test/java/com/singlestone/contacts/resources/data.sql @@ -0,0 +1,25 @@ +-- Contacts +insert into CONTACTS (street, city, state, zip, email, middle, first, last) +values('street1', 'city1', 'state1', 'zip1', 'e1@mail.com', 'a', 'a', 'a'); +insert into CONTACTS (street, city, state, zip, email, middle, first, last) +values('street2', 'city2', 'state2', 'zip2', 'e2@mail.com', 'a', 'b', 'a'); +insert into CONTACTS (street, city, state, zip, email, middle, first, last) +values('street3', 'city3', 'state3', 'zip3', 'e3@mail.com', 'a', 'b', 'b'); +insert into CONTACTS (street, city, state, zip, email, middle, first, last) +values('street4', 'city4', 'state4', 'zip4', 'e4@mail.com', 'a', 'a', 'b'); + +-- Phones +insert into PHONES (number, type, contact_id) +values('111-111-1111', 'HOME', 1); +insert into PHONES (number, type, contact_id) +values('222-222-2222', 'WORK', 1); +insert into PHONES (number, type, contact_id) +values('333-333-3333', 'WORK', 2); +insert into PHONES (number, type, contact_id) +values('444-444-4444', 'HOME', 2); +insert into PHONES (number, type, contact_id) +values('555-555-5555', 'MOBILE', 3); +insert into PHONES (number, type, contact_id) +values('777-777-7777', 'WORK', 4); +insert into PHONES (number, type, contact_id) +values('888-888-8888', 'HOME', 4); diff --git a/src/test/java/com/singlestone/contacts/service/ContactServiceTest.java b/src/test/java/com/singlestone/contacts/service/ContactServiceTest.java new file mode 100644 index 0000000..307e119 --- /dev/null +++ b/src/test/java/com/singlestone/contacts/service/ContactServiceTest.java @@ -0,0 +1,116 @@ +package com.singlestone.contacts.service; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +import com.singlestone.contacts.model.Address; +import com.singlestone.contacts.model.Contact; +import com.singlestone.contacts.model.Name; +import com.singlestone.contacts.model.Phone; +import com.singlestone.contacts.model.dto.ContactDTO; +import com.singlestone.contacts.repository.ContactRepository; +import com.singlestone.contacts.repository.PhoneRepository; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.beans.factory.annotation.Autowired; + +@ExtendWith(MockitoExtension.class) +public class ContactServiceTest { + + @Mock + private ContactRepository contactRepository; + + @Mock + private PhoneRepository phoneRepository; + + @Autowired + @InjectMocks + private ContactService contactService; + + private Contact createTestContact() { + Contact testContact = new Contact(); + + Name name = new Name(); + name.setFirst("first"); + name.setMiddle("middle"); + name.setLast("last"); + testContact.setName(name); + + Address address = new Address(); + address.setStreet("street"); + address.setCity("city"); + address.setState("state"); + address.setZip("zip"); + + List phones = new ArrayList<>(); + phones.add(new Phone("111-111-1111", "home")); + + testContact.setPhone(phones); + testContact.setEmail("e@mail.com"); + + return testContact; + } + + @Test + void testCreateContact() { + Contact contact = createTestContact(); + when(contactRepository.save(any())).thenReturn(contact); + contactService.createContact(new ContactDTO(contact)); + verify(contactRepository, times(1)).save(any()); + } + + @Test + void testGetAllContacts() { + List contacts = new ArrayList<>(); + contacts.add(createTestContact()); + when(contactRepository.findAll()).thenReturn(contacts); + contactService.getAllContacts(); + verify(contactRepository, times(1)).findAll(); + } + + @Test + void testGetContact() { + when(contactRepository.findById(anyLong())).thenReturn(Optional.of(createTestContact())); + contactService.getContact(1); + verify(contactRepository, times(1)).findById(anyLong()); + } + + @Test + void testUpdateContact() { + Contact testContact = createTestContact(); + testContact.setId(1L); + when(contactRepository.findById(anyLong())).thenReturn(Optional.of(testContact)); + contactService.updateContact(1, new ContactDTO(testContact)); + verify(contactRepository, times(1)).findById(anyLong()); + verify(contactRepository, times(1)).save(any()); + } + + @Test + void testDeleteContact() { + when(contactRepository.findById(anyLong())).thenReturn(Optional.of(createTestContact())); + contactService.deleteContact(1); + verify(contactRepository, times(1)).deleteById(anyLong()); + } + + @Test + void testGetCallList() { + List phones = new ArrayList<>(); + Phone testPhone = new Phone("111-111-1111", "home"); + testPhone.setContact(createTestContact()); + phones.add(testPhone); + when(phoneRepository.findByType(any(), any())).thenReturn(phones); + contactService.getCallList(); + verify(phoneRepository, times(1)).findByType(any(), any()); + } +}