/** * Copyright (C) 2010-2017 Gordon Fraser, Andrea Arcuri and EvoSuite * contributors * * This file is part of EvoSuite. * * EvoSuite is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation, either version 3.0 of the License, or * (at your option) any later version. * * EvoSuite 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 * Lesser Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with EvoSuite. If not, see <http://www.gnu.org/licenses/>. */ package org.evosuite.strategy; import java.text.NumberFormat; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; import org.evosuite.Properties; import org.evosuite.ShutdownTestWriter; import org.evosuite.Properties.Criterion; import org.evosuite.coverage.TestFitnessFactory; import org.evosuite.rmi.ClientServices; import org.evosuite.ga.FitnessFunction; import org.evosuite.ga.metaheuristics.GeneticAlgorithm; import org.evosuite.ga.stoppingconditions.MaxStatementsStoppingCondition; import org.evosuite.ga.stoppingconditions.StoppingCondition; import org.evosuite.statistics.RuntimeVariable; import org.evosuite.testcase.execution.ExecutionResult; import org.evosuite.testcase.execution.ExecutionTracer; import org.evosuite.testcase.TestChromosome; import org.evosuite.testcase.TestFitnessFunction; import org.evosuite.testsuite.TestSuiteChromosome; import org.evosuite.testsuite.TestSuiteFitnessFunction; import org.evosuite.testsuite.TestSuiteMinimizer; import org.evosuite.testsuite.factories.FixedSizeTestSuiteChromosomeFactory; import org.evosuite.utils.ArrayUtil; import org.evosuite.utils.LoggingUtils; import org.evosuite.utils.Randomness; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * This strategy selects one coverage goal at a time * and generates a test that satisfies it. * * The order of goals is randomized. Coincidental coverage is * checked. * * @author gordon * */ public class IndividualTestStrategy extends TestGenerationStrategy { private static final Logger logger = LoggerFactory.getLogger(IndividualTestStrategy.class); @Override public TestSuiteChromosome generateTests() { // Set up search algorithm LoggingUtils.getEvoLogger().info("* Setting up search algorithm for individual test generation"); ExecutionTracer.enableTraceCalls(); PropertiesTestGAFactory factory = new PropertiesTestGAFactory(); List<TestSuiteFitnessFunction> fitnessFunctions = getFitnessFunctions(); long start_time = System.currentTimeMillis() / 1000; // Get list of goals List<TestFitnessFactory<? extends TestFitnessFunction>> goalFactories = getFitnessFactories(); // long goalComputationStart = System.currentTimeMillis(); List<TestFitnessFunction> goals = new ArrayList<TestFitnessFunction>(); LoggingUtils.getEvoLogger().info("* Total number of test goals: "); for (TestFitnessFactory<? extends TestFitnessFunction> goalFactory : goalFactories) { goals.addAll(goalFactory.getCoverageGoals()); LoggingUtils.getEvoLogger().info(" - " + goalFactory.getClass().getSimpleName().replace("CoverageFactory", "") + " " + goalFactory.getCoverageGoals().size()); } if(!canGenerateTestsForSUT()) { LoggingUtils.getEvoLogger().info("* Found no testable methods in the target class " + Properties.TARGET_CLASS); ClientServices.getInstance().getClientNode().trackOutputVariable(RuntimeVariable.Total_Goals, goals.size()); return new TestSuiteChromosome(); } // Need to shuffle goals because the order may make a difference if (Properties.SHUFFLE_GOALS) { // LoggingUtils.getEvoLogger().info("* Shuffling goals"); Randomness.shuffle(goals); } ClientServices.getInstance().getClientNode().trackOutputVariable(RuntimeVariable.Total_Goals, goals.size()); LoggingUtils.getEvoLogger().info("* Total number of test goals: " + goals.size()); // Bootstrap with random testing to cover easy goals //statistics.searchStarted(suiteGA); StoppingCondition stoppingCondition = getStoppingCondition(); TestSuiteChromosome suite = (TestSuiteChromosome) bootstrapRandomSuite(fitnessFunctions.get(0), goalFactories.get(0)); // FIXME: just one fitness and one factory?! Set<Integer> covered = new HashSet<Integer>(); int covered_goals = 0; int num = 0; for (TestFitnessFunction fitness_function : goals) { if (fitness_function.isCoveredBy(suite)) { covered.add(num); covered_goals++; } num++; } if (covered_goals > 0) LoggingUtils.getEvoLogger().info("* Random bootstrapping covered " + covered_goals + " test goals"); int total_goals = goals.size(); if (covered_goals == total_goals) zeroFitness.setFinished(); int current_budget = 0; long total_budget = Properties.SEARCH_BUDGET; LoggingUtils.getEvoLogger().info("* Budget: " + NumberFormat.getIntegerInstance().format(total_budget)); while (current_budget < total_budget && covered_goals < total_goals && !globalTime.isFinished() && !ShutdownTestWriter.isInterrupted()) { long budget = (total_budget - current_budget) / (total_goals - covered_goals); logger.info("Budget: " + budget + "/" + (total_budget - current_budget)); logger.info("Statements: " + current_budget + "/" + total_budget); logger.info("Goals covered: " + covered_goals + "/" + total_goals); stoppingCondition.setLimit(budget); num = 0; // int num_statements = 0; // //MaxStatementsStoppingCondition.getNumExecutedStatements(); for (TestFitnessFunction fitnessFunction : goals) { if (covered.contains(num)) { num++; continue; } GeneticAlgorithm<TestChromosome> ga = factory.getSearchAlgorithm(); // ga.resetStoppingConditions(); // ga.clearPopulation(); //ga.setChromosomeFactory(getChromosomeFactory(fitnessFunction)); if (Properties.PRINT_CURRENT_GOALS) LoggingUtils.getEvoLogger().info("* Searching for goal " + num + ": " + fitnessFunction.toString()); logger.info("Goal " + num + "/" + (total_goals - covered_goals) + ": " + fitnessFunction); if (ShutdownTestWriter.isInterrupted()) { num++; continue; } if (globalTime.isFinished()) { LoggingUtils.getEvoLogger().info("Skipping goal because time is up"); num++; continue; } // FitnessFunction fitness_function = new ga.addFitnessFunction(fitnessFunction); // Perform search logger.info("Starting evolution for goal " + fitnessFunction); ga.generateSolution(); if (ga.getBestIndividual().getFitness() == 0.0) { if (Properties.PRINT_COVERED_GOALS) LoggingUtils.getEvoLogger().info("* Covered!"); // : " + // fitness_function.toString()); logger.info("Found solution, adding to test suite at " + MaxStatementsStoppingCondition.getNumExecutedStatements()); TestChromosome best = (TestChromosome) ga.getBestIndividual(); best.getTestCase().addCoveredGoal(fitnessFunction); suite.addTest(best); // Calculate and keep track of overall fitness for (TestSuiteFitnessFunction fitness_function : fitnessFunctions) fitness_function.getFitness(suite); covered_goals++; covered.add(num); // experiment: if (Properties.SKIP_COVERED) { Set<Integer> additional_covered_nums = getAdditionallyCoveredGoals(goals, covered, best); // LoggingUtils.getEvoLogger().info("Additionally covered: "+additional_covered_nums.size()); for (Integer covered_num : additional_covered_nums) { covered_goals++; covered.add(covered_num); } } } else { logger.info("Found no solution for " + fitnessFunction + " at " + MaxStatementsStoppingCondition.getNumExecutedStatements()); } //statistics.iteration(suiteGA); if (Properties.REUSE_BUDGET) current_budget += stoppingCondition.getCurrentValue(); else current_budget += budget + 1; // print console progress bar if (Properties.SHOW_PROGRESS && !(Properties.PRINT_COVERED_GOALS || Properties.PRINT_CURRENT_GOALS)) { double percent = current_budget; percent = percent / total_budget * 100; double coverage = covered_goals; coverage = coverage / total_goals * 100; // ConsoleProgressBar.printProgressBar((int) percent, (int) // coverage); } if (current_budget > total_budget) break; num++; // break; } } if (Properties.SHOW_PROGRESS) LoggingUtils.getEvoLogger().info(""); // for testing purposes if (globalTime.isFinished()) LoggingUtils.getEvoLogger().info("! Timeout reached"); if (current_budget >= total_budget) LoggingUtils.getEvoLogger().info("! Budget exceeded"); else LoggingUtils.getEvoLogger().info("* Remaining budget: " + (total_budget - current_budget)); // stoppingCondition.setLimit(Properties.SEARCH_BUDGET); // stoppingCondition.forceCurrentValue(current_budget); // suiteGA.setStoppingCondition(stopping_condition); // suiteGA.addStoppingCondition(global_time); // printBudget(suiteGA); int c = 0; int uncovered_goals = total_goals - covered_goals; if (uncovered_goals < 10) for (TestFitnessFunction goal : goals) { if (!covered.contains(c)) { LoggingUtils.getEvoLogger().info("! Unable to cover goal " + c + " " + goal.toString()); } c++; } else LoggingUtils.getEvoLogger().info("! #Goals that were not covered: " + uncovered_goals); //statistics.searchFinished(suiteGA); long end_time = System.currentTimeMillis() / 1000; LoggingUtils.getEvoLogger().info("* Search finished after " + (end_time - start_time) + "s, " + current_budget + " statements, best individual has fitness " + suite.getFitness()); // Search is finished, send statistics sendExecutionStatistics(); LoggingUtils.getEvoLogger().info("* Covered " + covered_goals + "/" + goals.size() + " goals"); logger.info("Resulting test suite: " + suite.size() + " tests, length " + suite.totalLengthOfTestCases()); return suite; } private Set<Integer> getAdditionallyCoveredGoals( List<? extends TestFitnessFunction> goals, Set<Integer> covered, TestChromosome best) { Set<Integer> r = new HashSet<Integer>(); ExecutionResult result = best.getLastExecutionResult(); assert (result != null); // if (result == null) { // result = TestCaseExecutor.getInstance().execute(best.test); // } int num = -1; for (TestFitnessFunction goal : goals) { num++; if (covered.contains(num)) continue; if (goal.isCovered(best, result)) { r.add(num); if (Properties.PRINT_COVERED_GOALS) LoggingUtils.getEvoLogger().info("* Additionally covered: " + goal.toString()); } } return r; } private TestSuiteChromosome bootstrapRandomSuite(FitnessFunction<?> fitness, TestFitnessFactory<?> goals) { if (ArrayUtil.contains(Properties.CRITERION, Criterion.DEFUSE) || ArrayUtil.contains(Properties.CRITERION, Criterion.ALLDEFS)) { LoggingUtils.getEvoLogger().info("* Disabled random bootstraping for dataflow criterion"); Properties.RANDOM_TESTS = 0; } if (Properties.RANDOM_TESTS > 0) { LoggingUtils.getEvoLogger().info("* Bootstrapping initial random test suite"); } // else // LoggingUtils.getEvoLogger().info("* Bootstrapping initial random test suite disabled!"); FixedSizeTestSuiteChromosomeFactory factory = new FixedSizeTestSuiteChromosomeFactory(Properties.RANDOM_TESTS); TestSuiteChromosome suite = factory.getChromosome(); if (Properties.RANDOM_TESTS > 0) { TestSuiteMinimizer minimizer = new TestSuiteMinimizer(goals); minimizer.minimize(suite, true); LoggingUtils.getEvoLogger().info("* Initial test suite contains " + suite.size() + " tests"); } return suite; } }