• [Unit Testing Java] Unit testing with Mockito vs. integration testing


    Service:

    package com.example.ec.service;
    
    import com.example.ec.domain.Tour;
    import com.example.ec.domain.TourRating;
    import com.example.ec.repo.TourRatingRepository;
    import com.example.ec.repo.TourRepository;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.data.domain.Page;
    import org.springframework.data.domain.Pageable;
    import org.springframework.stereotype.Service;
    
    import javax.transaction.Transactional;
    import java.util.*;
    
    /**
     * Tour Rating Service
     *
     * Created by Mary Ellen Bowman.
     */
    
    @Service
    @Transactional
    public class TourRatingService {
        private TourRatingRepository tourRatingRepository;
        private TourRepository tourRepository;
    
        /**
         * Construct TourRatingService
         *
         * @param tourRatingRepository Tour Rating Repository
         * @param tourRepository Tour Repository
         */
        @Autowired
        public TourRatingService(TourRatingRepository tourRatingRepository, TourRepository tourRepository) {
            this.tourRatingRepository = tourRatingRepository;
            this.tourRepository = tourRepository;
        }
    
        /**
         * Create a new Tour Rating in the database
         *
         * @param tourId tour identifier
         * @param customerId customer identifier
         * @param score score of the tour rating
         * @param comment additional comment
         * @throws NoSuchElementException if no Tour found.
         */
        public void createNew(int tourId, Integer customerId, Integer score, String comment) throws NoSuchElementException {
            tourRatingRepository.save(new TourRating(verifyTour(tourId), customerId,
                    score, comment));
        }
    
        /**
         * Get All Ratings.
         *
         * @return List of TourRatings
         */
        public List<TourRating> lookupAll()  {
            return tourRatingRepository.findAll();
        }
    
        public Optional<TourRating> lookupRatingById(int id)  {
            return tourRatingRepository.findById(id);
        }
    
        /**
         * Get a page of tour ratings for a tour.
         *
         * @param tourId tour identifier
         * @param pageable page parameters to determine which elements to fetch
         * @return Page of TourRatings
         * @throws NoSuchElementException if no Tour found.
         */
        public Page<TourRating> lookupRatings(int tourId, Pageable pageable) throws NoSuchElementException  {
            return tourRatingRepository.findByTourId(verifyTour(tourId).getId(), pageable);
        }
    
        /**
         * Update some of the elements of a Tour Rating.
         *
         * @param tourId tour identifier
         * @param score score of the tour rating
         * @param comment additional comment
         * @return Tour Rating Domain Object
         * @throws NoSuchElementException if no Tour found.
         */
        public TourRating update(int tourId, Integer customerId, Integer score, String comment) throws NoSuchElementException {
            TourRating rating = verifyTourRating(tourId, customerId);
            rating.setScore(score);
            rating.setComment(comment);
            return tourRatingRepository.save(rating);
        }
    
        /**
         * Update all of the elements of a Tour Rating.
         *
         * @param tourId tour identifier
         * @param customerId customer identifier
         * @param score score of the tour rating
         * @param comment additional comment
         * @return Tour Rating Domain Object
         * @throws NoSuchElementException if no Tour found.
         */
        public TourRating updateSome(int tourId, Integer customerId, Integer score, String comment)
                throws NoSuchElementException {
            TourRating rating = verifyTourRating(tourId, customerId);
            if (score != null) {
                rating.setScore(score);
            }
            if (comment!= null) {
                rating.setComment(comment);
            }
            return tourRatingRepository.save(rating);
        }
    
        /**
         * Delete a Tour Rating.
         *
         * @param tourId tour identifier
         * @param customerId customer identifier
         * @throws NoSuchElementException if no Tour found.
         */
        public void delete(int tourId, Integer customerId) throws NoSuchElementException {
            TourRating rating = verifyTourRating(tourId, customerId);
            tourRatingRepository.delete(rating);
        }
        /**
         * Get the average score of a tour.
         *
         * @param tourId tour identifier
         * @return average score as a Double.
         * @throws NoSuchElementException
         */
        public Double getAverageScore(int tourId)  throws NoSuchElementException  {
            List<TourRating> ratings = tourRatingRepository.findByTourId(verifyTour(tourId).getId());
            OptionalDouble average = ratings.stream().mapToInt((rating) -> rating.getScore()).average();
            return average.isPresent() ? average.getAsDouble():null;
        }
        /**
         * Service for many customers to give the same score for a service
         * @param tourId
         * @param score
         * @param customers
         */
    
        public void rateMany(int tourId,  int score, Integer [] customers) {
    
            Tour tour = tourRepository.findById(tourId).orElseThrow(() -> new NoSuchElementException("rateMany, no valid tourId"));
            for (Integer c : customers) {
                tourRatingRepository.save(new TourRating(tour, c, score));
            }
        }
    
        /**
         * Verify and return the Tour given a tourId.
         *
         * @param tourId
         * @return the found Tour
         * @throws NoSuchElementException if no Tour found.
         */
        private Tour verifyTour(int tourId) throws NoSuchElementException {
            return tourRepository.findById(tourId).orElseThrow(() ->
                    new NoSuchElementException("Tour does not exist " + tourId)
            );
        }
    
    
        /**
         * Verify and return the TourRating for a particular tourId and Customer
         * @param tourId
         * @param customerId
         * @return the found TourRating
         * @throws NoSuchElementException if no TourRating found
         */
        private TourRating verifyTourRating(int tourId, int customerId) throws NoSuchElementException {
            return tourRatingRepository.findByTourIdAndCustomerId(tourId, customerId).orElseThrow(() ->
                    new NoSuchElementException("Tour-Rating pair for request("
                            + tourId + " for customer" + customerId));
        }
    
    
    }

    Unit testing:

    package com.example.ec.service;
    
    import com.example.ec.domain.Tour;
    import com.example.ec.domain.TourRating;
    import com.example.ec.repo.TourRatingRepository;
    import com.example.ec.repo.TourRepository;
    import org.junit.Before;
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.mockito.ArgumentCaptor;
    import org.mockito.InjectMocks;
    import org.mockito.Mock;
    import org.mockito.junit.MockitoJUnitRunner;
    import org.springframework.data.domain.Page;
    import org.springframework.data.domain.Pageable;
    
    import java.util.Arrays;
    import java.util.Optional;
    
    import static org.hamcrest.CoreMatchers.is;
    import static org.junit.Assert.assertThat;
    import static org.mockito.Mockito.*;
    
    @RunWith(MockitoJUnitRunner.class)
    public class TourRatingServiceTest {
    
        private static final int CUSTOMER_ID = 123;
        private static final int TOUR_ID = 1;
        private static final int TOUR_RATING_ID = 100;
    
        @Mock
        private TourRepository tourRepositoryMock;
    
        @Mock
        TourRatingRepository tourRatingRepositoryMock;
    
        // will inject tourRepositoryMock, tourRatingRepositoryMock to service
        @InjectMocks
        private TourRatingService service;
    
        @Mock
        private Tour tourMock;
    
        @Mock
        private TourRating tourRatingMock;
    
        /**
         * Mock Response to commonly invoked methods
         */
        @Before
        public void setupReturnValuesOfMockMethods() {
            when(tourRepositoryMock.findById(TOUR_ID)).thenReturn(Optional.of(tourMock));
            when(tourMock.getId()).thenReturn(TOUR_ID);
            when(tourRatingRepositoryMock.findByTourIdAndCustomerId(TOUR_ID,CUSTOMER_ID)).thenReturn(Optional.of(tourRatingMock));
            when(tourRatingRepositoryMock.findByTourId(TOUR_ID)).thenReturn(Arrays.asList(tourRatingMock));
        }
    
        @Test
        public void lookupRatingById() {
            when(tourRatingRepositoryMock.findById(TOUR_RATING_ID)).thenReturn(Optional.of(tourRatingMock));
    
            //invoke and verify lookupRatingById
            assertThat(service.lookupRatingById(TOUR_RATING_ID).get(), is(tourRatingMock));
        }
    
        @Test
        public void lookupAll() {
            when(tourRatingRepositoryMock.findAll()).thenReturn(Arrays.asList(tourRatingMock));
    
            //invoke and verify lookupAll
            assertThat(service.lookupAll().get(0), is(tourRatingMock));
        }
    
        @Test
        public void getAverageScore() {
            when(tourRatingMock.getScore()).thenReturn(10);
    
            //invoke and verify getAverageScore
            assertThat(service.getAverageScore(TOUR_ID), is(10.0));
        }
    
        @Test
        public void lookupRatings() {
            //create mocks of Pageable and Page (only needed in this test)
            Pageable pageable = mock(Pageable.class);
            Page page = mock(Page.class);
            when(tourRatingRepositoryMock.findByTourId(1, pageable)).thenReturn(page);
    
            //invoke and verify lookupRatings
            assertThat(service.lookupRatings(TOUR_ID, pageable), is(page));
        }
        /**************************************************************************************
         *
         * Verify the invocation of dependencies.
         *
         **************************************************************************************/
    
        @Test
        public void delete() {
            //invoke delete
            service.delete(1,CUSTOMER_ID);
    
            //verify tourRatingRepository.delete invoked
            verify(tourRatingRepositoryMock).delete(any(TourRating.class));
        }
    
        @Test
        public void rateMany() {
            //invoke rateMany
            service.rateMany(TOUR_ID, 10, new Integer[]{CUSTOMER_ID, CUSTOMER_ID + 1});
    
            //verify tourRatingRepository.save invoked twice
            verify(tourRatingRepositoryMock, times(2)).save(any(TourRating.class));
        }
    
        @Test
        public void update() {
            //invoke update
            service.update(TOUR_ID,CUSTOMER_ID,5, "great");
    
            //verify tourRatingRepository.save invoked once
            verify(tourRatingRepositoryMock).save(any(TourRating.class));
    
            //verify and tourRating setter methods invoked
            verify(tourRatingMock).setComment("great");
            verify(tourRatingMock).setScore(5);
        }
    
        @Test
        public void updateSome() {
            //invoke updateSome
            service.updateSome(TOUR_ID, CUSTOMER_ID, 1, "awful");
    
            //verify tourRatingRepository.save invoked once
            verify(tourRatingRepositoryMock).save(any(TourRating.class));
    
            //verify and tourRating setter methods invoked
            verify(tourRatingMock).setComment("awful");
            verify(tourRatingMock).setScore(1);
        }
    
        /**************************************************************************************
         *
         * Verify the invocation of dependencies
         * Capture parameter values.
         * Verify the parameters.
         *
         **************************************************************************************/
    
        @Test
        public void createNew() {
            //prepare to capture a TourRating Object
            ArgumentCaptor<TourRating> tourRatingCaptor = ArgumentCaptor.forClass(TourRating.class);
    
            //invoke createNew
            service.createNew(TOUR_ID, CUSTOMER_ID, 2, "ok");
    
            //verify tourRatingRepository.save invoked once and capture the TourRating Object
            verify(tourRatingRepositoryMock).save(tourRatingCaptor.capture());
    
            //verify the attributes of the Tour Rating Object
            assertThat(tourRatingCaptor.getValue().getTour(), is(tourMock));
            assertThat(tourRatingCaptor.getValue().getCustomerId(), is(CUSTOMER_ID));
            assertThat(tourRatingCaptor.getValue().getScore(), is(2));
            assertThat(tourRatingCaptor.getValue().getComment(), is("ok"));
        }
    }

    Integration testing:

    package com.example.ec.service;
    
    import com.example.ec.domain.TourRating;
    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.dao.DataIntegrityViolationException;
    import org.springframework.test.context.junit4.SpringRunner;
    import org.springframework.transaction.annotation.Transactional;
    
    import java.util.List;
    import java.util.NoSuchElementException;
    
    import static org.hamcrest.CoreMatchers.is;
    import static org.junit.Assert.assertThat;
    import static org.junit.Assert.assertTrue;
    
    /**
     * Created by Mary Ellen Bowman
     */
    @RunWith(SpringRunner.class)
    @SpringBootTest
    @Transactional
    public class TourRatingServiceIntegrationTest {
        private static final int CUSTOMER_ID = 456;
        private static final int TOUR_ID = 1;
        private static final int NOT_A_TOUR_ID = 123;
    
        @Autowired
        private TourRatingService service;
    
        //Happy Path delete existing TourRating.
        @Test
        public void delete() {
            List<TourRating> tourRatings = service.lookupAll();
            service.delete(tourRatings.get(0).getTour().getId(), tourRatings.get(0).getCustomerId());
            assertThat(service.lookupAll().size(), is(tourRatings.size() - 1));
        }
    
        //UnHappy Path, Tour NOT_A_TOUR_ID does not exist
        @Test(expected = NoSuchElementException.class)
        public void deleteException() {
            service.delete(NOT_A_TOUR_ID, 1234);
        }
    
    
        //Happy Path to Create a new Tour Rating
        @Test
        public void createNew() {
            //would throw NoSuchElementException if TourRating for TOUR_ID by CUSTOMER_ID already exists
            service.createNew(TOUR_ID, CUSTOMER_ID, 2, "it was fair");
    
            //Verify New Tour Rating created.
            TourRating newTourRating = service.verifyTourRating(TOUR_ID, CUSTOMER_ID);
            assertThat(newTourRating.getTour().getId(), is(TOUR_ID));
            assertThat(newTourRating.getCustomerId(), is(CUSTOMER_ID));
            assertThat(newTourRating.getScore(), is(2));
            assertThat(newTourRating.getComment(), is ("it was fair"));
        }
    
        //UnHappy Path, Tour NOT_A_TOUR_ID does not exist
        @Test(expected = NoSuchElementException.class)
        public void createNewException() {
            service.createNew(NOT_A_TOUR_ID, CUSTOMER_ID, 2, "it was fair");
        }
    
        //Happy Path many customers Rate one tour
        @Test
        public void rateMany() {
            int ratings = service.lookupAll().size();
            service.rateMany(TOUR_ID, 5, new Integer[]{100, 101, 102});
            assertThat(service.lookupAll().size(), is(ratings + 3));
        }
    
        //Unhappy Path, 2nd Invocation would create duplicates in the database, DataIntegrityViolationException thrown
        @Test(expected = DataIntegrityViolationException.class)
        public void rateManyProveRollback() {
            int ratings = service.lookupAll().size();
            Integer customers[] = {100, 101, 102};
            service.rateMany(TOUR_ID, 3, customers);
            service.rateMany(TOUR_ID, 3, customers);
        }
    
        //Happy Path, Update a Tour Rating already in the database
        @Test
        public void update() {
            createNew();
            TourRating tourRating = service.update(TOUR_ID, CUSTOMER_ID, 1, "one");
            assertThat(tourRating.getTour().getId(), is(TOUR_ID));
            assertThat(tourRating.getCustomerId(), is(CUSTOMER_ID));
            assertThat(tourRating.getScore(), is(1));
            assertThat(tourRating.getComment(), is("one"));
        }
    
        //Unhappy path, no Tour Rating exists for tourId=1 and customer=1
        @Test(expected = NoSuchElementException.class)
        public void updateException() throws Exception {
            service.update(1, 1, 1, "one");
        }
    
        //Happy Path, Update a Tour Rating already in the database
        @Test
        public void updateSome() {
            createNew();
            TourRating tourRating = service.update(TOUR_ID, CUSTOMER_ID, 1, "one");
            assertThat(tourRating.getTour().getId(), is(TOUR_ID));
            assertThat(tourRating.getCustomerId(), is(CUSTOMER_ID));
            assertThat(tourRating.getScore(), is(1));
            assertThat(tourRating.getComment(), is("one"));
        }
    
        //Unhappy path, no Tour Rating exists for tourId=1 and customer=1
        @Test(expected = NoSuchElementException.class)
        public void updateSomeException() throws Exception {
            service.update(1, 1, 1, "one");
        }
    
        //Happy Path get average score of a Tour.
        @Test
        public void getAverageScore() {
            assertTrue(service.getAverageScore(TOUR_ID) == 4.0);
        }
    
        //UnHappy Path, Tour NOT_A_TOUR_ID does not exist
        @Test(expected = NoSuchElementException.class)
        public void getAverageScoreException() {
            service.getAverageScore(NOT_A_TOUR_ID); //That tour does not exist
        }
    }
  • 相关阅读:
    可爱的中国电信 请问我们的电脑还属于我们自己吗?
    了解客户的需求,写出的代码或许才是最优秀的............
    DELPHI DATASNAP 入门操作(3)简单的主从表的简单更新【含简单事务处理】
    用数组公式获取字符在字符串中最后出现的位置
    在ehlib的DBGridEh控件中使用过滤功能(可以不用 MemTableEh 控件 适用ehlib 5.2 ehlib 5.3)
    格式化json返回的时间
    ExtJs中使用Ajax赋值给全局变量异常解决方案
    java compiler level does not match the version of the installed java project facet (转)
    收集的资料(六)ASP.NET编程中的十大技巧
    收集的资料共享出来(五)Asp.Net 权限解决办法
  • 原文地址:https://www.cnblogs.com/Answer1215/p/14176526.html
Copyright © 2020-2023  润新知