com.ciphertool.genetics.algorithms.MultigenerationalGeneticAlgorithmTest.java Source code

Java tutorial

Introduction

Here is the source code for com.ciphertool.genetics.algorithms.MultigenerationalGeneticAlgorithmTest.java

Source

/**
 * Copyright 2015 George Belden
 * 
 * This file is part of ZodiacGenetics.
 * 
 * ZodiacGenetics is free software: you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the Free
 * Software Foundation, either version 3 of the License, or (at your option) any
 * later version.
 * 
 * ZodiacGenetics is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
 * details.
 * 
 * You should have received a copy of the GNU General Public License along with
 * ZodiacGenetics. If not, see <http://www.gnu.org/licenses/>.
 */

package com.ciphertool.genetics.algorithms;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyListOf;
import static org.mockito.Matchers.eq;
import static org.mockito.Matchers.same;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;

import org.junit.Test;
import org.springframework.util.ReflectionUtils;

import com.ciphertool.genetics.GeneticAlgorithmStrategy;
import com.ciphertool.genetics.Population;
import com.ciphertool.genetics.algorithms.crossover.CrossoverAlgorithm;
import com.ciphertool.genetics.algorithms.mutation.MutationAlgorithm;
import com.ciphertool.genetics.algorithms.mutation.NonUniformMutationAlgorithm;
import com.ciphertool.genetics.algorithms.selection.SelectionAlgorithm;
import com.ciphertool.genetics.algorithms.selection.modes.Selector;
import com.ciphertool.genetics.dao.ExecutionStatisticsDao;
import com.ciphertool.genetics.entities.Chromosome;
import com.ciphertool.genetics.entities.statistics.ExecutionStatistics;
import com.ciphertool.genetics.entities.statistics.GenerationStatistics;
import com.ciphertool.genetics.fitness.FitnessEvaluator;
import com.ciphertool.genetics.mocks.MockKeylessChromosome;

public class MultigenerationalGeneticAlgorithmTest {
    private static final double DEFAULT_FITNESS_VALUE = 100.0;

    @Test
    public void testSetPopulation() {
        Population populationToSet = mock(Population.class);

        MultigenerationalGeneticAlgorithm multigenerationalGeneticAlgorithm = new MultigenerationalGeneticAlgorithm();
        multigenerationalGeneticAlgorithm.setPopulation(populationToSet);

        Population populationFromObject = multigenerationalGeneticAlgorithm.getPopulation();

        assertSame(populationToSet, populationFromObject);
    }

    @Test
    public void testSetExecutionStatisticsDao() {
        ExecutionStatisticsDao executionStatisticsDaoToSet = mock(ExecutionStatisticsDao.class);

        MultigenerationalGeneticAlgorithm multigenerationalGeneticAlgorithm = new MultigenerationalGeneticAlgorithm();
        multigenerationalGeneticAlgorithm.setExecutionStatisticsDao(executionStatisticsDaoToSet);

        Field executionStatisticsDaoField = ReflectionUtils.findField(MultigenerationalGeneticAlgorithm.class,
                "executionStatisticsDao");
        ReflectionUtils.makeAccessible(executionStatisticsDaoField);
        ExecutionStatisticsDao executionStatisticsDaoFromObject = (ExecutionStatisticsDao) ReflectionUtils
                .getField(executionStatisticsDaoField, multigenerationalGeneticAlgorithm);

        assertSame(executionStatisticsDaoToSet, executionStatisticsDaoFromObject);
    }

    @Test
    public void testSetStrategy() {
        GeneticAlgorithmStrategy strategyToSet = new GeneticAlgorithmStrategy();

        Population populationMock = mock(Population.class);
        CrossoverAlgorithm crossoverAlgorithmMock = mock(CrossoverAlgorithm.class);
        NonUniformMutationAlgorithm mutationAlgorithmMock = mock(NonUniformMutationAlgorithm.class);
        SelectionAlgorithm selectionAlgorithmMock = mock(SelectionAlgorithm.class);
        FitnessEvaluator fitnessEvaluatorMock = mock(FitnessEvaluator.class);
        FitnessEvaluator knownSolutionFitnessEvaluatorMock = mock(FitnessEvaluator.class);
        Object geneticStructure = new Object();
        int lifeSpan = 10;
        boolean compareToKnownSolution = true;
        boolean mutateDuringCrossover = true;
        int maxMutationsPerIndividual = 5;

        strategyToSet.setGeneticStructure(geneticStructure);
        strategyToSet.setFitnessEvaluator(fitnessEvaluatorMock);
        strategyToSet.setLifespan(lifeSpan);
        strategyToSet.setKnownSolutionFitnessEvaluator(knownSolutionFitnessEvaluatorMock);
        strategyToSet.setCompareToKnownSolution(compareToKnownSolution);
        strategyToSet.setCrossoverAlgorithm(crossoverAlgorithmMock);
        strategyToSet.setMutationAlgorithm(mutationAlgorithmMock);
        strategyToSet.setMutateDuringCrossover(mutateDuringCrossover);
        strategyToSet.setMaxMutationsPerIndividual(maxMutationsPerIndividual);
        strategyToSet.setSelectionAlgorithm(selectionAlgorithmMock);

        MultigenerationalGeneticAlgorithm multigenerationalGeneticAlgorithm = new MultigenerationalGeneticAlgorithm();
        multigenerationalGeneticAlgorithm.setPopulation(populationMock);
        multigenerationalGeneticAlgorithm.setStrategy(strategyToSet);

        Field strategyField = ReflectionUtils.findField(MultigenerationalGeneticAlgorithm.class, "strategy");
        ReflectionUtils.makeAccessible(strategyField);
        GeneticAlgorithmStrategy strategyFromObject = (GeneticAlgorithmStrategy) ReflectionUtils
                .getField(strategyField, multigenerationalGeneticAlgorithm);

        assertSame(strategyToSet, strategyFromObject);
        verify(populationMock, times(1)).setGeneticStructure(same(geneticStructure));
        verify(populationMock, times(1)).setFitnessEvaluator(same(fitnessEvaluatorMock));
        verify(populationMock, times(1)).setLifespan(eq(lifeSpan));
        verify(populationMock, times(1)).setKnownSolutionFitnessEvaluator(same(knownSolutionFitnessEvaluatorMock));
        verify(populationMock, times(1)).setCompareToKnownSolution(eq(compareToKnownSolution));
        verifyNoMoreInteractions(populationMock);

        verify(crossoverAlgorithmMock, times(1)).setMutationAlgorithm(same(mutationAlgorithmMock));
        verify(crossoverAlgorithmMock, times(1)).setMutateDuringCrossover(eq(mutateDuringCrossover));
        verifyNoMoreInteractions(crossoverAlgorithmMock);

        verify(mutationAlgorithmMock, times(1)).setMaxMutationsPerChromosome(eq(maxMutationsPerIndividual));
        verifyNoMoreInteractions(mutationAlgorithmMock);

        Field crossoverAlgorithmField = ReflectionUtils.findField(MultigenerationalGeneticAlgorithm.class,
                "crossoverAlgorithm");
        ReflectionUtils.makeAccessible(crossoverAlgorithmField);
        CrossoverAlgorithm crossoverAlgorithmFromObject = (CrossoverAlgorithm) ReflectionUtils
                .getField(crossoverAlgorithmField, multigenerationalGeneticAlgorithm);

        assertSame(crossoverAlgorithmMock, crossoverAlgorithmFromObject);

        Field mutationAlgorithmField = ReflectionUtils.findField(MultigenerationalGeneticAlgorithm.class,
                "mutationAlgorithm");
        ReflectionUtils.makeAccessible(mutationAlgorithmField);
        MutationAlgorithm mutationAlgorithmFromObject = (MutationAlgorithm) ReflectionUtils
                .getField(mutationAlgorithmField, multigenerationalGeneticAlgorithm);

        assertSame(mutationAlgorithmMock, mutationAlgorithmFromObject);

        Field selectionAlgorithmField = ReflectionUtils.findField(MultigenerationalGeneticAlgorithm.class,
                "selectionAlgorithm");
        ReflectionUtils.makeAccessible(selectionAlgorithmField);
        SelectionAlgorithm selectionAlgorithmFromObject = (SelectionAlgorithm) ReflectionUtils
                .getField(selectionAlgorithmField, multigenerationalGeneticAlgorithm);

        assertSame(selectionAlgorithmMock, selectionAlgorithmFromObject);
    }

    @Test
    public void testInitialize() {
        Date beforeInitialize = new Date();

        GeneticAlgorithmStrategy strategyToSet = new GeneticAlgorithmStrategy();
        int populationSize = 100;
        int lifeSpan = 0;
        double survivalRate = 0.1;
        double mutationRate = 0.0;
        double crossoverRate = 0.0;
        CrossoverAlgorithm crossoverAlgorithmMock = mock(CrossoverAlgorithm.class);
        FitnessEvaluator fitnessEvaluatorMock = mock(FitnessEvaluator.class);
        MutationAlgorithm mutationAlgorithmMock = mock(MutationAlgorithm.class);
        strategyToSet.setGeneticStructure(new Object());
        strategyToSet.setPopulationSize(populationSize);
        strategyToSet.setLifespan(lifeSpan);
        strategyToSet.setSurvivalRate(survivalRate);
        strategyToSet.setMutationRate(mutationRate);
        strategyToSet.setMaxMutationsPerIndividual(0);
        strategyToSet.setCrossoverRate(crossoverRate);
        strategyToSet.setMutateDuringCrossover(false);
        strategyToSet.setMaxGenerations(-1);
        strategyToSet.setCrossoverAlgorithm(crossoverAlgorithmMock);
        strategyToSet.setFitnessEvaluator(fitnessEvaluatorMock);
        strategyToSet.setMutationAlgorithm(mutationAlgorithmMock);
        strategyToSet.setSelectionAlgorithm(mock(SelectionAlgorithm.class));
        strategyToSet.setSelector(mock(Selector.class));

        Population populationMock = mock(Population.class);

        MultigenerationalGeneticAlgorithm multigenerationalGeneticAlgorithm = new MultigenerationalGeneticAlgorithm();
        multigenerationalGeneticAlgorithm.setPopulation(populationMock);

        Field strategyField = ReflectionUtils.findField(MultigenerationalGeneticAlgorithm.class, "strategy");
        ReflectionUtils.makeAccessible(strategyField);
        ReflectionUtils.setField(strategyField, multigenerationalGeneticAlgorithm, strategyToSet);

        Field generationCountField = ReflectionUtils.findField(MultigenerationalGeneticAlgorithm.class,
                "generationCount");
        ReflectionUtils.makeAccessible(generationCountField);
        ReflectionUtils.setField(generationCountField, multigenerationalGeneticAlgorithm, 1);

        Field stopRequestedField = ReflectionUtils.findField(MultigenerationalGeneticAlgorithm.class,
                "stopRequested");
        ReflectionUtils.makeAccessible(stopRequestedField);
        ReflectionUtils.setField(stopRequestedField, multigenerationalGeneticAlgorithm, true);

        Field executionStatisticsField = ReflectionUtils.findField(MultigenerationalGeneticAlgorithm.class,
                "executionStatistics");
        ReflectionUtils.makeAccessible(executionStatisticsField);
        ExecutionStatistics executionStatisticsFromObject = (ExecutionStatistics) ReflectionUtils
                .getField(executionStatisticsField, multigenerationalGeneticAlgorithm);
        assertNull(executionStatisticsFromObject);

        multigenerationalGeneticAlgorithm.initialize();

        int generationCountFromObject = (int) ReflectionUtils.getField(generationCountField,
                multigenerationalGeneticAlgorithm);
        boolean stopRequestedFromObject = (boolean) ReflectionUtils.getField(stopRequestedField,
                multigenerationalGeneticAlgorithm);
        executionStatisticsFromObject = (ExecutionStatistics) ReflectionUtils.getField(executionStatisticsField,
                multigenerationalGeneticAlgorithm);

        assertEquals(0, generationCountFromObject);
        assertFalse(stopRequestedFromObject);
        assertNotNull(executionStatisticsFromObject);
        assertTrue(executionStatisticsFromObject.getStartDateTime().getTime() >= beforeInitialize.getTime());
        assertEquals(populationSize, executionStatisticsFromObject.getPopulationSize().intValue());
        assertEquals(lifeSpan, executionStatisticsFromObject.getLifespan().intValue());
        assertEquals(new Double(survivalRate), executionStatisticsFromObject.getSurvivalRate());
        assertEquals(new Double(mutationRate), executionStatisticsFromObject.getMutationRate());
        assertEquals(new Double(crossoverRate), executionStatisticsFromObject.getCrossoverRate());
        assertEquals(crossoverAlgorithmMock.getClass().getSimpleName(),
                executionStatisticsFromObject.getCrossoverAlgorithm());
        assertEquals(fitnessEvaluatorMock.getClass().getSimpleName(),
                executionStatisticsFromObject.getFitnessEvaluator());
        assertEquals(mutationAlgorithmMock.getClass().getSimpleName(),
                executionStatisticsFromObject.getMutationAlgorithm());

        verify(populationMock, times(1)).clearIndividuals();
        verify(populationMock, times(1)).breed(eq(populationSize));
        verify(populationMock, times(1)).evaluateFitness(null);
        verify(populationMock, times(1)).size();
        verifyNoMoreInteractions(populationMock);
    }

    @Test
    public void testFinish() {
        Date beforeFinish = new Date();

        ExecutionStatisticsDao executionStatisticsDaoToSet = mock(ExecutionStatisticsDao.class);

        MultigenerationalGeneticAlgorithm multigenerationalGeneticAlgorithm = new MultigenerationalGeneticAlgorithm();
        multigenerationalGeneticAlgorithm.setExecutionStatisticsDao(executionStatisticsDaoToSet);

        ExecutionStatistics executionStatistics = new ExecutionStatistics();
        Field executionStatisticsField = ReflectionUtils.findField(MultigenerationalGeneticAlgorithm.class,
                "executionStatistics");
        ReflectionUtils.makeAccessible(executionStatisticsField);
        ReflectionUtils.setField(executionStatisticsField, multigenerationalGeneticAlgorithm, executionStatistics);

        Field generationCountField = ReflectionUtils.findField(MultigenerationalGeneticAlgorithm.class,
                "generationCount");
        ReflectionUtils.makeAccessible(generationCountField);
        ReflectionUtils.setField(generationCountField, multigenerationalGeneticAlgorithm, 1);

        multigenerationalGeneticAlgorithm.finish();

        assertTrue(executionStatistics.getEndDateTime().getTime() >= beforeFinish.getTime());

        verify(executionStatisticsDaoToSet, times(1)).insert(same(executionStatistics));

        ExecutionStatistics executionStatisticsFromObject = (ExecutionStatistics) ReflectionUtils
                .getField(executionStatisticsField, multigenerationalGeneticAlgorithm);
        assertNull(executionStatisticsFromObject);
    }

    @Test
    public void testProceedWithNextGeneration() {
        MultigenerationalGeneticAlgorithm multigenerationalGeneticAlgorithm = new MultigenerationalGeneticAlgorithm();

        int initialPopulationSize = 100;
        int populationSize = 100;
        int index = 0;
        double survivalRate = 0.9;
        double mutationRate = 0.1;
        double crossoverRate = 0.1;

        Population populationMock = mock(Population.class);

        List<Chromosome> individuals = new ArrayList<Chromosome>();
        for (int i = 0; i < initialPopulationSize; i++) {
            individuals.add(new MockKeylessChromosome());
        }

        when(populationMock.selectIndex()).thenReturn(index);
        when(populationMock.getIndividuals()).thenReturn(individuals);
        when(populationMock.size()).thenReturn(initialPopulationSize);
        when(populationMock.selectIndex()).thenReturn(0);
        multigenerationalGeneticAlgorithm.setPopulation(populationMock);

        GeneticAlgorithmStrategy strategyToSet = new GeneticAlgorithmStrategy();
        strategyToSet.setPopulationSize(populationSize);
        strategyToSet.setSurvivalRate(survivalRate);
        strategyToSet.setMutationRate(mutationRate);
        strategyToSet.setCrossoverRate(crossoverRate);

        Field strategyField = ReflectionUtils.findField(MultigenerationalGeneticAlgorithm.class, "strategy");
        ReflectionUtils.makeAccessible(strategyField);
        ReflectionUtils.setField(strategyField, multigenerationalGeneticAlgorithm, strategyToSet);

        SelectionAlgorithm selectionAlgorithmMock = mock(SelectionAlgorithm.class);

        Field selectionAlgorithmField = ReflectionUtils.findField(MultigenerationalGeneticAlgorithm.class,
                "selectionAlgorithm");
        ReflectionUtils.makeAccessible(selectionAlgorithmField);
        ReflectionUtils.setField(selectionAlgorithmField, multigenerationalGeneticAlgorithm,
                selectionAlgorithmMock);

        Field generationCountField = ReflectionUtils.findField(MultigenerationalGeneticAlgorithm.class,
                "generationCount");
        ReflectionUtils.makeAccessible(generationCountField);
        ReflectionUtils.setField(generationCountField, multigenerationalGeneticAlgorithm, 0);

        MutationAlgorithm mutationAlgorithmMock = mock(MutationAlgorithm.class);
        Field mutationAlgorithmField = ReflectionUtils.findField(MultigenerationalGeneticAlgorithm.class,
                "mutationAlgorithm");
        ReflectionUtils.makeAccessible(mutationAlgorithmField);
        ReflectionUtils.setField(mutationAlgorithmField, multigenerationalGeneticAlgorithm, mutationAlgorithmMock);

        CrossoverAlgorithm crossoverAlgorithmMock = mock(CrossoverAlgorithm.class);

        Field crossoverAlgorithmField = ReflectionUtils.findField(MultigenerationalGeneticAlgorithm.class,
                "crossoverAlgorithm");
        ReflectionUtils.makeAccessible(crossoverAlgorithmField);
        ReflectionUtils.setField(crossoverAlgorithmField, multigenerationalGeneticAlgorithm,
                crossoverAlgorithmMock);

        Chromosome chromosomeToReturn = new MockKeylessChromosome();
        when(crossoverAlgorithmMock.crossover(any(Chromosome.class), any(Chromosome.class)))
                .thenReturn(Arrays.asList(chromosomeToReturn));

        ExecutionStatistics executionStatistics = new ExecutionStatistics();
        Field executionStatisticsField = ReflectionUtils.findField(MultigenerationalGeneticAlgorithm.class,
                "executionStatistics");
        ReflectionUtils.makeAccessible(executionStatisticsField);
        ReflectionUtils.setField(executionStatisticsField, multigenerationalGeneticAlgorithm, executionStatistics);

        assertEquals(0, executionStatistics.getGenerationStatisticsList().size());

        multigenerationalGeneticAlgorithm.proceedWithNextGeneration();

        assertEquals(1, executionStatistics.getGenerationStatisticsList().size());

        /*
         * The population size should be reduced by the number of parents used
         * during crossover.
         */
        assertEquals(100, populationMock.size());

        int generationCountFromObject = (int) ReflectionUtils.getField(generationCountField,
                multigenerationalGeneticAlgorithm);
        assertEquals(1, generationCountFromObject);

        verify(selectionAlgorithmMock, times(1)).select(same(populationMock), eq(populationSize), eq(survivalRate));
        verifyNoMoreInteractions(selectionAlgorithmMock);

        verify(populationMock, times(30)).selectIndex();
        verify(populationMock, times(30)).getIndividuals();
        verify(populationMock, times(30)).makeIneligibleForReproduction(index);
        verify(populationMock, times(20)).addIndividualAsIneligible(any(Chromosome.class));
        verify(populationMock, times(5)).size();
        verify(populationMock, times(1)).increaseAge();
        verify(populationMock, times(1)).resetEligibility();
        verify(populationMock, times(1)).breed(populationSize);
        verify(populationMock, times(1)).evaluateFitness(any(GenerationStatistics.class));
        verifyNoMoreInteractions(populationMock);

        verify(mutationAlgorithmMock, times(10)).mutateChromosome(any(Chromosome.class));
        verifyNoMoreInteractions(mutationAlgorithmMock);

        verify(crossoverAlgorithmMock, times(10)).crossover(any(Chromosome.class), any(Chromosome.class));
        verifyNoMoreInteractions(crossoverAlgorithmMock);
    }

    @Test
    public void testValidateParameters_NoErrors() {
        MultigenerationalGeneticAlgorithm multigenerationalGeneticAlgorithm = new MultigenerationalGeneticAlgorithm();

        GeneticAlgorithmStrategy strategyToSet = new GeneticAlgorithmStrategy();
        strategyToSet.setGeneticStructure(new Object());
        strategyToSet.setPopulationSize(1);
        strategyToSet.setLifespan(0);
        strategyToSet.setSurvivalRate(0.1);
        strategyToSet.setMutationRate(0.0);
        strategyToSet.setMaxMutationsPerIndividual(0);
        strategyToSet.setCrossoverRate(0.0);
        strategyToSet.setMutateDuringCrossover(false);
        strategyToSet.setMaxGenerations(-1);
        strategyToSet.setCrossoverAlgorithm(mock(CrossoverAlgorithm.class));
        strategyToSet.setFitnessEvaluator(mock(FitnessEvaluator.class));
        strategyToSet.setMutationAlgorithm(mock(MutationAlgorithm.class));
        strategyToSet.setSelectionAlgorithm(mock(SelectionAlgorithm.class));
        strategyToSet.setSelector(mock(Selector.class));

        Field strategyField = ReflectionUtils.findField(MultigenerationalGeneticAlgorithm.class, "strategy");
        ReflectionUtils.makeAccessible(strategyField);
        ReflectionUtils.setField(strategyField, multigenerationalGeneticAlgorithm, strategyToSet);
    }

    @Test
    public void testValidateParameters_AllErrors() {
        MultigenerationalGeneticAlgorithm multigenerationalGeneticAlgorithm = new MultigenerationalGeneticAlgorithm();

        GeneticAlgorithmStrategy strategyToSet = new GeneticAlgorithmStrategy();
        strategyToSet.setGeneticStructure(null);
        strategyToSet.setPopulationSize(0);
        strategyToSet.setLifespan(null);

        /*
         * This must be set via reflection because the setter method does its
         * own validation
         */
        Field survivalRateField = ReflectionUtils.findField(GeneticAlgorithmStrategy.class, "survivalRate");
        ReflectionUtils.makeAccessible(survivalRateField);
        ReflectionUtils.setField(survivalRateField, strategyToSet, -0.1);

        /*
         * This must be set via reflection because the setter method does its
         * own validation
         */
        Field mutationRateField = ReflectionUtils.findField(GeneticAlgorithmStrategy.class, "mutationRate");
        ReflectionUtils.makeAccessible(mutationRateField);
        ReflectionUtils.setField(mutationRateField, strategyToSet, -0.1);

        strategyToSet.setMaxMutationsPerIndividual(-1);

        /*
         * This must be set via reflection because the setter method does its
         * own validation
         */
        Field crossoverRateField = ReflectionUtils.findField(GeneticAlgorithmStrategy.class, "crossoverRate");
        ReflectionUtils.makeAccessible(crossoverRateField);
        ReflectionUtils.setField(crossoverRateField, strategyToSet, -0.1);

        strategyToSet.setMutateDuringCrossover(null);
        strategyToSet.setMaxGenerations(0);
        strategyToSet.setCrossoverAlgorithm(null);
        strategyToSet.setFitnessEvaluator(null);
        strategyToSet.setMutationAlgorithm(null);
        strategyToSet.setSelectionAlgorithm(null);
        strategyToSet.setSelector(null);

        Field strategyField = ReflectionUtils.findField(MultigenerationalGeneticAlgorithm.class, "strategy");
        ReflectionUtils.makeAccessible(strategyField);
        ReflectionUtils.setField(strategyField, multigenerationalGeneticAlgorithm, strategyToSet);

        boolean exceptionCaught = false;

        try {
            multigenerationalGeneticAlgorithm.validateParameters();
        } catch (IllegalStateException ise) {
            String expectedMessage = "Unable to execute genetic algorithm because one or more of the required parameters are missing.  The validation errors are:";
            expectedMessage += "\n\t-Parameter 'geneticStructure' cannot be null.";
            expectedMessage += "\n\t-Parameter 'populationSize' must be greater than zero.";
            expectedMessage += "\n\t-Parameter 'lifespan' cannot be null.";
            expectedMessage += "\n\t-Parameter 'survivalRate' must be greater than zero.";
            expectedMessage += "\n\t-Parameter 'mutationRate' must be greater than or equal to zero.";
            expectedMessage += "\n\t-Parameter 'maxMutationsPerIndividual' must be greater than or equal to zero.";
            expectedMessage += "\n\t-Parameter 'crossoverRate' must be greater than or equal to zero.";
            expectedMessage += "\n\t-Parameter 'mutateDuringCrossover' cannot be null.";
            expectedMessage += "\n\t-Parameter 'maxGenerations' cannot be null and must not equal zero.";
            expectedMessage += "\n\t-Parameter 'crossoverAlgorithm' cannot be null.";
            expectedMessage += "\n\t-Parameter 'fitnessEvaluator' cannot be null.";
            expectedMessage += "\n\t-Parameter 'mutationAlgorithm' cannot be null.";
            expectedMessage += "\n\t-Parameter 'selectionAlgorithm' cannot be null.";
            expectedMessage += "\n\t-Parameter 'selectorMethod' cannot be null.";

            assertEquals(expectedMessage, ise.getMessage());

            exceptionCaught = true;
        }

        assertTrue(exceptionCaught);
    }

    @Test
    public void testSelect() {
        MultigenerationalGeneticAlgorithm multigenerationalGeneticAlgorithm = new MultigenerationalGeneticAlgorithm();

        int populationSize = 100;
        double survivalRate = 0.9;

        Population population = new Population();
        multigenerationalGeneticAlgorithm.setPopulation(population);

        GeneticAlgorithmStrategy strategyToSet = new GeneticAlgorithmStrategy();
        strategyToSet.setPopulationSize(populationSize);
        strategyToSet.setSurvivalRate(survivalRate);

        Field strategyField = ReflectionUtils.findField(MultigenerationalGeneticAlgorithm.class, "strategy");
        ReflectionUtils.makeAccessible(strategyField);
        ReflectionUtils.setField(strategyField, multigenerationalGeneticAlgorithm, strategyToSet);

        SelectionAlgorithm selectionAlgorithmMock = mock(SelectionAlgorithm.class);

        Field selectionAlgorithmField = ReflectionUtils.findField(MultigenerationalGeneticAlgorithm.class,
                "selectionAlgorithm");
        ReflectionUtils.makeAccessible(selectionAlgorithmField);
        ReflectionUtils.setField(selectionAlgorithmField, multigenerationalGeneticAlgorithm,
                selectionAlgorithmMock);

        multigenerationalGeneticAlgorithm.select();

        verify(selectionAlgorithmMock, times(1)).select(same(population), eq(populationSize), eq(survivalRate));
        verifyNoMoreInteractions(selectionAlgorithmMock);
    }

    @SuppressWarnings("unchecked")
    @Test
    public void testCrossover() {
        MultigenerationalGeneticAlgorithm multigenerationalGeneticAlgorithm = new MultigenerationalGeneticAlgorithm();

        Population population = new Population();
        FitnessEvaluator fitnessEvaluatorMock = mock(FitnessEvaluator.class);
        when(fitnessEvaluatorMock.evaluate(any(Chromosome.class))).thenReturn(DEFAULT_FITNESS_VALUE);
        population.setFitnessEvaluator(fitnessEvaluatorMock);

        Selector selectorMock = mock(Selector.class);
        population.setSelector(selectorMock);
        when(selectorMock.getNextIndex(anyListOf(Chromosome.class), any(Double.class))).thenReturn(0, 1, 2, 3, 4);

        int initialPopulationSize = 50;

        for (int i = 0; i < initialPopulationSize; i++) {
            population.addIndividual(new MockKeylessChromosome());
        }

        multigenerationalGeneticAlgorithm.setPopulation(population);

        CrossoverAlgorithm crossoverAlgorithmMock = mock(CrossoverAlgorithm.class);

        Field crossoverAlgorithmField = ReflectionUtils.findField(MultigenerationalGeneticAlgorithm.class,
                "crossoverAlgorithm");
        ReflectionUtils.makeAccessible(crossoverAlgorithmField);
        ReflectionUtils.setField(crossoverAlgorithmField, multigenerationalGeneticAlgorithm,
                crossoverAlgorithmMock);

        Chromosome chromosomeToReturn = new MockKeylessChromosome();
        when(crossoverAlgorithmMock.crossover(any(Chromosome.class), any(Chromosome.class)))
                .thenReturn(Arrays.asList(chromosomeToReturn));

        GeneticAlgorithmStrategy strategy = new GeneticAlgorithmStrategy();
        strategy.setCrossoverRate(0.1);

        Field strategyField = ReflectionUtils.findField(MultigenerationalGeneticAlgorithm.class, "strategy");
        ReflectionUtils.makeAccessible(strategyField);
        ReflectionUtils.setField(strategyField, multigenerationalGeneticAlgorithm, strategy);

        Field ineligibleForReproductionField = ReflectionUtils.findField(Population.class,
                "ineligibleForReproduction");
        ReflectionUtils.makeAccessible(ineligibleForReproductionField);
        List<Chromosome> ineligibleForReproductionFromObject = (List<Chromosome>) ReflectionUtils
                .getField(ineligibleForReproductionField, population);

        assertEquals(0, ineligibleForReproductionFromObject.size());

        int childrenProduced = multigenerationalGeneticAlgorithm.crossover(initialPopulationSize);

        ineligibleForReproductionFromObject = (List<Chromosome>) ReflectionUtils
                .getField(ineligibleForReproductionField, population);

        assertEquals(5, childrenProduced);

        /*
         * The population size should be reduced by the number of parents used
         * during crossover.
         */
        assertEquals(40, population.size());

        // There should be 10 ineligible parents, along with the 5 children
        assertEquals(15, ineligibleForReproductionFromObject.size());

        verify(selectorMock, times(10)).getNextIndex(anyListOf(Chromosome.class), any(Double.class));

        verify(crossoverAlgorithmMock, times(5)).crossover(any(Chromosome.class), any(Chromosome.class));
    }

    @SuppressWarnings("unchecked")
    @Test
    public void testCrossover_SmallPopulation() {
        MultigenerationalGeneticAlgorithm multigenerationalGeneticAlgorithm = new MultigenerationalGeneticAlgorithm();

        Population population = new Population();

        Chromosome chromosome = new MockKeylessChromosome();
        population.addIndividual(chromosome);
        multigenerationalGeneticAlgorithm.setPopulation(population);

        CrossoverAlgorithm crossoverAlgorithmMock = mock(CrossoverAlgorithm.class);

        Field crossoverAlgorithmField = ReflectionUtils.findField(MultigenerationalGeneticAlgorithm.class,
                "crossoverAlgorithm");
        ReflectionUtils.makeAccessible(crossoverAlgorithmField);
        ReflectionUtils.setField(crossoverAlgorithmField, multigenerationalGeneticAlgorithm,
                crossoverAlgorithmMock);

        Field ineligibleForReproductionField = ReflectionUtils.findField(Population.class,
                "ineligibleForReproduction");
        ReflectionUtils.makeAccessible(ineligibleForReproductionField);
        List<Chromosome> ineligibleForReproductionFromObject = (List<Chromosome>) ReflectionUtils
                .getField(ineligibleForReproductionField, population);

        assertEquals(0, ineligibleForReproductionFromObject.size());

        int childrenProduced = multigenerationalGeneticAlgorithm.crossover(10);

        ineligibleForReproductionFromObject = (List<Chromosome>) ReflectionUtils
                .getField(ineligibleForReproductionField, population);

        assertEquals(1, population.size());

        assertEquals(0, childrenProduced);

        assertEquals(0, ineligibleForReproductionFromObject.size());

        verifyZeroInteractions(crossoverAlgorithmMock);
    }

    @Test
    public void testDeterminePairsToCrossover() {
        int initialPopulationSize = 100;

        Population populationMock = mock(Population.class);
        when(populationMock.size()).thenReturn(initialPopulationSize);

        MultigenerationalGeneticAlgorithm multigenerationalGeneticAlgorithm = new MultigenerationalGeneticAlgorithm();
        multigenerationalGeneticAlgorithm.setPopulation(populationMock);

        GeneticAlgorithmStrategy strategyToSet = new GeneticAlgorithmStrategy();
        double crossoverRate = 0.5;
        strategyToSet.setCrossoverRate(crossoverRate);

        Field strategyField = ReflectionUtils.findField(MultigenerationalGeneticAlgorithm.class, "strategy");
        ReflectionUtils.makeAccessible(strategyField);
        ReflectionUtils.setField(strategyField, multigenerationalGeneticAlgorithm, strategyToSet);

        long pairsToCrossover = multigenerationalGeneticAlgorithm.determinePairsToCrossover(initialPopulationSize);

        assertEquals(50, pairsToCrossover);
    }

    @Test
    public void testDeterminePairsToCrossover_SmallPopulation() {
        int initialPopulationSize = 100;
        int actualPopulationSize = 50;

        Population populationMock = mock(Population.class);
        when(populationMock.size()).thenReturn(actualPopulationSize);

        MultigenerationalGeneticAlgorithm multigenerationalGeneticAlgorithm = new MultigenerationalGeneticAlgorithm();
        multigenerationalGeneticAlgorithm.setPopulation(populationMock);

        GeneticAlgorithmStrategy strategyToSet = new GeneticAlgorithmStrategy();
        double crossoverRate = 0.5;
        strategyToSet.setCrossoverRate(crossoverRate);

        Field strategyField = ReflectionUtils.findField(MultigenerationalGeneticAlgorithm.class, "strategy");
        ReflectionUtils.makeAccessible(strategyField);
        ReflectionUtils.setField(strategyField, multigenerationalGeneticAlgorithm, strategyToSet);

        long pairsToCrossover = multigenerationalGeneticAlgorithm.determinePairsToCrossover(initialPopulationSize);

        assertEquals(25, pairsToCrossover);
    }

    @Test
    public void testMutate() {
        int initialPopulationSize = 100;
        int index = 0;

        Population populationMock = mock(Population.class);
        when(populationMock.selectIndex()).thenReturn(index);
        when(populationMock.getIndividuals()).thenReturn(Arrays.asList(mock(Chromosome.class)));
        when(populationMock.size()).thenReturn(initialPopulationSize);

        MultigenerationalGeneticAlgorithm multigenerationalGeneticAlgorithm = new MultigenerationalGeneticAlgorithm();
        multigenerationalGeneticAlgorithm.setPopulation(populationMock);

        GeneticAlgorithmStrategy strategyToSet = new GeneticAlgorithmStrategy();
        double mutationRate = 0.5;
        strategyToSet.setMutationRate(mutationRate);

        Field strategyField = ReflectionUtils.findField(MultigenerationalGeneticAlgorithm.class, "strategy");
        ReflectionUtils.makeAccessible(strategyField);
        ReflectionUtils.setField(strategyField, multigenerationalGeneticAlgorithm, strategyToSet);

        MutationAlgorithm mutationAlgorithmMock = mock(MutationAlgorithm.class);
        Field mutationAlgorithmField = ReflectionUtils.findField(MultigenerationalGeneticAlgorithm.class,
                "mutationAlgorithm");
        ReflectionUtils.makeAccessible(mutationAlgorithmField);
        ReflectionUtils.setField(mutationAlgorithmField, multigenerationalGeneticAlgorithm, mutationAlgorithmMock);

        multigenerationalGeneticAlgorithm.mutate(initialPopulationSize);

        verify(populationMock, times(50)).selectIndex();
        verify(populationMock, times(50)).getIndividuals();
        verify(populationMock, times(50)).makeIneligibleForReproduction(index);
        verify(populationMock, times(50)).addIndividualAsIneligible(any(Chromosome.class));
        verify(populationMock, times(1)).size();
        verifyNoMoreInteractions(populationMock);

        verify(mutationAlgorithmMock, times(50)).mutateChromosome(any(Chromosome.class));
        verifyNoMoreInteractions(mutationAlgorithmMock);
    }

    @Test
    public void testMutate_SmallPopulation() {
        int initialPopulationSize = 100;
        int actualPopulationSize = 25;
        int index = 0;

        Population populationMock = mock(Population.class);
        when(populationMock.selectIndex()).thenReturn(index);
        when(populationMock.getIndividuals()).thenReturn(Arrays.asList(mock(Chromosome.class)));
        when(populationMock.size()).thenReturn(actualPopulationSize);

        MultigenerationalGeneticAlgorithm multigenerationalGeneticAlgorithm = new MultigenerationalGeneticAlgorithm();
        multigenerationalGeneticAlgorithm.setPopulation(populationMock);

        GeneticAlgorithmStrategy strategyToSet = new GeneticAlgorithmStrategy();
        double mutationRate = 0.5;
        strategyToSet.setMutationRate(mutationRate);

        Field strategyField = ReflectionUtils.findField(MultigenerationalGeneticAlgorithm.class, "strategy");
        ReflectionUtils.makeAccessible(strategyField);
        ReflectionUtils.setField(strategyField, multigenerationalGeneticAlgorithm, strategyToSet);

        MutationAlgorithm mutationAlgorithmMock = mock(MutationAlgorithm.class);
        Field mutationAlgorithmField = ReflectionUtils.findField(MultigenerationalGeneticAlgorithm.class,
                "mutationAlgorithm");
        ReflectionUtils.makeAccessible(mutationAlgorithmField);
        ReflectionUtils.setField(mutationAlgorithmField, multigenerationalGeneticAlgorithm, mutationAlgorithmMock);

        multigenerationalGeneticAlgorithm.mutate(initialPopulationSize);

        verify(populationMock, times(actualPopulationSize)).selectIndex();
        verify(populationMock, times(actualPopulationSize)).getIndividuals();
        verify(populationMock, times(actualPopulationSize)).makeIneligibleForReproduction(index);
        verify(populationMock, times(actualPopulationSize)).addIndividualAsIneligible(any(Chromosome.class));
        verify(populationMock, times(1)).size();
        verifyNoMoreInteractions(populationMock);

        verify(mutationAlgorithmMock, times(actualPopulationSize)).mutateChromosome(any(Chromosome.class));
        verifyNoMoreInteractions(mutationAlgorithmMock);
    }

    @Test
    public void testSpawnInitialPopulation() {
        GeneticAlgorithmStrategy strategyToSet = new GeneticAlgorithmStrategy();
        int populationSize = 100;
        strategyToSet.setPopulationSize(populationSize);

        Population populationMock = mock(Population.class);

        MultigenerationalGeneticAlgorithm multigenerationalGeneticAlgorithm = new MultigenerationalGeneticAlgorithm();
        multigenerationalGeneticAlgorithm.setPopulation(populationMock);

        Field strategyField = ReflectionUtils.findField(MultigenerationalGeneticAlgorithm.class, "strategy");
        ReflectionUtils.makeAccessible(strategyField);
        ReflectionUtils.setField(strategyField, multigenerationalGeneticAlgorithm, strategyToSet);

        multigenerationalGeneticAlgorithm.spawnInitialPopulation();

        verify(populationMock, times(1)).clearIndividuals();
        verify(populationMock, times(1)).breed(eq(populationSize));
        verify(populationMock, times(1)).evaluateFitness(null);
        verify(populationMock, times(1)).size();
        verifyNoMoreInteractions(populationMock);
    }

    @Test
    public void testPersistStatistics() {
        ExecutionStatisticsDao executionStatisticsDaoToSet = mock(ExecutionStatisticsDao.class);

        MultigenerationalGeneticAlgorithm multigenerationalGeneticAlgorithm = new MultigenerationalGeneticAlgorithm();
        multigenerationalGeneticAlgorithm.setExecutionStatisticsDao(executionStatisticsDaoToSet);

        ExecutionStatistics executionStatistics = new ExecutionStatistics();
        Field executionStatisticsField = ReflectionUtils.findField(MultigenerationalGeneticAlgorithm.class,
                "executionStatistics");
        ReflectionUtils.makeAccessible(executionStatisticsField);
        ReflectionUtils.setField(executionStatisticsField, multigenerationalGeneticAlgorithm, executionStatistics);

        multigenerationalGeneticAlgorithm.persistStatistics();

        verify(executionStatisticsDaoToSet, times(1)).insert(same(executionStatistics));
    }

    @Test
    public void testRequestStop() {
        MultigenerationalGeneticAlgorithm multigenerationalGeneticAlgorithm = new MultigenerationalGeneticAlgorithm();

        Field stopRequestedField = ReflectionUtils.findField(MultigenerationalGeneticAlgorithm.class,
                "stopRequested");
        ReflectionUtils.makeAccessible(stopRequestedField);
        boolean stopRequestedFromObject = (boolean) ReflectionUtils.getField(stopRequestedField,
                multigenerationalGeneticAlgorithm);

        assertEquals(false, stopRequestedFromObject);

        multigenerationalGeneticAlgorithm.requestStop();

        stopRequestedFromObject = (boolean) ReflectionUtils.getField(stopRequestedField,
                multigenerationalGeneticAlgorithm);

        assertEquals(true, stopRequestedFromObject);
    }
}