zoukankan      html  css  js  c++  java
  • [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
        }
    }
  • 相关阅读:
    python中对一个列表进行乱序
    GPU比CPU慢?可能模型太简单
    VLAN之间单臂路由通信
    数据结构_顺序栈的代码实践
    MarkDown语法学习
    【转载】给想要入门渗透的人的忠告——schiz0wcingU
    SQL注入原理及绕过安全狗
    Python学习---字符串处理
    【转载】RAID写惩罚(Write Penalty)与IOPS计算
    Kali安装使用文泉驿字体
  • 原文地址:https://www.cnblogs.com/Answer1215/p/14176526.html
Copyright © 2011-2022 走看看