Skip to content

Latest commit

 

History

History
301 lines (254 loc) · 8.58 KB

05-2-B-Spring-Testing.adoc

File metadata and controls

301 lines (254 loc) · 8.58 KB

Unit Testing Persistence in the Backend Service

  1. In a fresh Spring Boot project, there is already a single test class EventRegistrationApplicationTests in the src/test/java folder that looks like the following:

    package ca.mcgill.ecse321.eventregistration;
    
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.test.context.SpringBootTest;
    import org.springframework.test.context.junit4.SpringRunner;
    
    @RunWith(SpringRunner.class)
    @SpringBootTest
    public class EventRegistrationApplicationTests {
    
        @Test
        public void contextLoads() {
    
        }
    
    }
  2. Run this test that checks if the application can successfully load by right clicking on the class → Run as…​ → JUnit test

    Important
    You need to set the SPRING_DATASOURCE_URL for the test run configuration as well if you use an environment variable to set datasource URL. See step 5 in section 3.3.1.
  3. Add a new test class ca.mcgill.ecse321.eventregistration.service.TestEventRegistrationService and implement tests for the service

    package ca.mcgill.ecse321.eventregistration.service;
    
    import static org.junit.Assert.assertEquals;
    import static org.junit.Assert.fail;
    
    import java.sql.Date;
    import java.sql.Time;
    import java.time.LocalTime;
    import java.time.format.DateTimeFormatter;
    import java.util.Calendar;
    import java.util.List;
    
    import org.junit.After;
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.test.context.SpringBootTest;
    import org.springframework.test.context.junit4.SpringRunner;
    
    import ca.mcgill.ecse321.eventregistration.dao.EventRepository;
    import ca.mcgill.ecse321.eventregistration.dao.PersonRepository;
    import ca.mcgill.ecse321.eventregistration.dao.RegistrationRepository;
    import ca.mcgill.ecse321.eventregistration.model.Event;
    import ca.mcgill.ecse321.eventregistration.model.Person;
    
    @RunWith(SpringRunner.class)
    @SpringBootTest
    public class TestEventRegistrationService {
    
    	@Autowired
    	private EventRegistrationService service;
    
    	@Autowired
    	private PersonRepository personRepository;
    	@Autowired
    	private EventRepository eventRepository;
    	@Autowired
    	private RegistrationRepository registrationRepository;
    
    	@After
    	public void clearDatabase() {
    		// Fisrt, we clear registrations to avoid exceptions due to inconsistencies
    		registrationRepository.deleteAll();
    		// Then we can clear the other tables
    		personRepository.deleteAll();
    		eventRepository.deleteAll();
    	}
    
    	@Test
    	public void testCreatePerson() {
    		assertEquals(0, service.getAllPersons().size());
    
    		String name = "Oscar";
    
    		try {
    			service.createPerson(name);
    		} catch (IllegalArgumentException e) {
    			// Check that no error occurred
    			fail();
    		}
    
    		List<Person> allPersons = service.getAllPersons();
    
    		assertEquals(1, allPersons.size());
    		assertEquals(name, allPersons.get(0).getName());
    	}
    
    	@Test
    	public void testCreatePersonNull() {
    		assertEquals(0, service.getAllPersons().size());
    
    		String name = null;
    		String error = null;
    
    		try {
    			service.createPerson(name);
    		} catch (IllegalArgumentException e) {
    			error = e.getMessage();
    		}
    
    		// check error
    		assertEquals("Person name cannot be empty!", error);
    
    		// check no change in memory
    		assertEquals(0, service.getAllPersons().size());
    
    	}
    
        // ... other tests
    
        @Test
    	public void testRegisterPersonAndEventDoNotExist() {
    		assertEquals(0, service.getAllRegistrations().size());
    
    		String nameP = "Oscar";
    		Person person = new Person();
    		person.setName(nameP);
    		assertEquals(0, service.getAllPersons().size());
    
    		String nameE = "Soccer Game";
    		Calendar c = Calendar.getInstance();
    		c.set(2016, Calendar.OCTOBER, 16, 9, 00, 0);
    		Date eventDate = new Date(c.getTimeInMillis());
    		Time startTime = new Time(c.getTimeInMillis());
    		c.set(2016, Calendar.OCTOBER, 16, 10, 30, 0);
    		Time endTime = new Time(c.getTimeInMillis());
    		Event event = new Event();
    		event.setName(nameE);
    		event.setDate(eventDate);
    		event.setStartTime(startTime);
    		event.setEndTime(endTime);
    		assertEquals(0, service.getAllEvents().size());
    
    		String error = null;
    		try {
    			service.register(person, event);
    		} catch (IllegalArgumentException e) {
    			error = e.getMessage();
    		}
    
    		// check error
    		assertEquals("Person does not exist! Event does not exist!", error);
    
    		// check model in memory
    		assertEquals(0, service.getAllRegistrations().size());
    		assertEquals(0, service.getAllPersons().size());
    		assertEquals(0, service.getAllEvents().size());
    
    	}
    
    
        // ... other tests
    }
  4. See the complete test suite here.

  5. Run the tests and interpret the test error messages! You should see only a few (at least one) tests passing.

  6. Update the implementation (i.e., replace the current service method codes with the ones provided below) of the following methods with input validation in the EventRegistrationService service class to make the tests pass (Test-Driven Development)

    @Transactional
    public Person createPerson(String name) {
    	if (name == null || name.trim().length() == 0) {
    		throw new IllegalArgumentException("Person name cannot be empty!");
    	}
    	Person person = new Person();
    	person.setName(name);
    	personRepository.save(person);
    	return person;
    }
    @Transactional
    public Person getPerson(String name) {
        if (name == null || name.trim().length() == 0) {
            throw new IllegalArgumentException("Person name cannot be empty!");
        }
        Person person = personRepository.findPersonByName(name);
        return person;
    }
    @Transactional
    public Event getEvent(String name) {
        if (name == null || name.trim().length() == 0) {
            throw new IllegalArgumentException("Event name cannot be empty!");
        }
        Event event = eventRepository.findEventByName(name);
        return event;
    }
    @Transactional
    public Event createEvent(String name, Date date, Time startTime, Time endTime) {
        // Input validation
        String error = "";
        if (name == null || name.trim().length() == 0) {
            error = error + "Event name cannot be empty! ";
        }
        if (date == null) {
            error = error + "Event date cannot be empty! ";
        }
        if (startTime == null) {
            error = error + "Event start time cannot be empty! ";
        }
        if (endTime == null) {
            error = error + "Event end time cannot be empty! ";
        }
        if (endTime != null && startTime != null && endTime.before(startTime)) {
            error = error + "Event end time cannot be before event start time!";
        }
        error = error.trim();
        if (error.length() > 0) {
            throw new IllegalArgumentException(error);
        }
    
        Event event = new Event();
        event.setName(name);
        event.setDate(date);
        event.setStartTime(startTime);
        event.setEndTime(endTime);
        eventRepository.save(event);
        return event;
    }
    @Transactional
    public Registration register(Person person, Event event) {
        String error = "";
        if (person == null) {
            error = error + "Person needs to be selected for registration! ";
        } else if (!personRepository.existsById(person.getName())) {
            error = error + "Person does not exist! ";
        }
        if (event == null) {
            error = error + "Event needs to be selected for registration!";
        } else if (!eventRepository.existsById(event.getName())) {
            error = error + "Event does not exist!";
        }
        if (registrationRepository.existsByPersonAndEvent(person, event)) {
            error = error + "Person is already registered to this event!";
        }
        error = error.trim();
    
        if (error.length() > 0) {
            throw new IllegalArgumentException(error);
        }
    
        Registration registration = new Registration();
    	registration.setId(person.getName().hashCode() * event.getName().hashCode());
        registration.setPerson(person);
        registration.setEvent(event);
    
        registrationRepository.save(registration);
    
        return registration;
    }
    @Transactional
    public List<Event> getEventsAttendedByPerson(Person person) {
        if (person == null ) {
            throw new IllegalArgumentException("Person cannot be null!");
        }
        List<Event> eventsAttendedByPerson = new ArrayList<>();
        for (Registration r : registrationRepository.findByPerson(person)) {
            eventsAttendedByPerson.add(r.getEvent());
        }
        return eventsAttendedByPerson;
    }
  7. Run the tests again, and all should be passing this time.