001package org.junit.runner; 002 003import java.io.IOException; 004import java.io.ObjectInputStream; 005import java.io.ObjectOutputStream; 006import java.io.ObjectStreamClass; 007import java.io.ObjectStreamField; 008import java.io.Serializable; 009import java.util.ArrayList; 010import java.util.Collections; 011import java.util.List; 012import java.util.concurrent.CopyOnWriteArrayList; 013import java.util.concurrent.atomic.AtomicInteger; 014import java.util.concurrent.atomic.AtomicLong; 015 016import org.junit.runner.notification.Failure; 017import org.junit.runner.notification.RunListener; 018 019/** 020 * A <code>Result</code> collects and summarizes information from running multiple tests. 021 * All tests are counted -- additional information is collected from tests that fail. 022 * 023 * @since 4.0 024 */ 025public class Result implements Serializable { 026 private static final long serialVersionUID = 1L; 027 private static final ObjectStreamField[] serialPersistentFields = 028 ObjectStreamClass.lookup(SerializedForm.class).getFields(); 029 private final AtomicInteger count; 030 private final AtomicInteger ignoreCount; 031 private final AtomicInteger assumptionFailureCount; 032 private final CopyOnWriteArrayList<Failure> failures; 033 private final AtomicLong runTime; 034 private final AtomicLong startTime; 035 036 /** Only set during deserialization process. */ 037 private SerializedForm serializedForm; 038 039 public Result() { 040 count = new AtomicInteger(); 041 ignoreCount = new AtomicInteger(); 042 assumptionFailureCount = new AtomicInteger(); 043 failures = new CopyOnWriteArrayList<Failure>(); 044 runTime = new AtomicLong(); 045 startTime = new AtomicLong(); 046 } 047 048 private Result(SerializedForm serializedForm) { 049 count = serializedForm.fCount; 050 ignoreCount = serializedForm.fIgnoreCount; 051 assumptionFailureCount = serializedForm.assumptionFailureCount; 052 failures = new CopyOnWriteArrayList<Failure>(serializedForm.fFailures); 053 runTime = new AtomicLong(serializedForm.fRunTime); 054 startTime = new AtomicLong(serializedForm.fStartTime); 055 } 056 057 /** 058 * Returns the number of tests run 059 */ 060 public int getRunCount() { 061 return count.get(); 062 } 063 064 /** 065 * Returns the number of tests that failed during the run 066 */ 067 public int getFailureCount() { 068 return failures.size(); 069 } 070 071 /** 072 * Returns the number of milliseconds it took to run the entire suite to run 073 */ 074 public long getRunTime() { 075 return runTime.get(); 076 } 077 078 /** 079 * Returns the {@link Failure}s describing tests that failed and the problems they encountered 080 */ 081 public List<Failure> getFailures() { 082 return failures; 083 } 084 085 /** 086 * @return the number of tests ignored during the run 087 */ 088 public int getIgnoreCount() { 089 return ignoreCount.get(); 090 } 091 092 /** 093 * Returns the number of tests skipped because of an assumption failure 094 * 095 * @throws UnsupportedOperationException if the result was serialized in a version before JUnit 4.13 096 * @since 4.13 097 */ 098 public int getAssumptionFailureCount() { 099 if (assumptionFailureCount == null) { 100 throw new UnsupportedOperationException( 101 "Result was serialized from a version of JUnit that doesn't support this method"); 102 } 103 return assumptionFailureCount.get(); 104 } 105 106 /** 107 * @return <code>true</code> if all tests succeeded 108 */ 109 public boolean wasSuccessful() { 110 return getFailureCount() == 0; 111 } 112 113 private void writeObject(ObjectOutputStream s) throws IOException { 114 SerializedForm serializedForm = new SerializedForm(this); 115 serializedForm.serialize(s); 116 } 117 118 private void readObject(ObjectInputStream s) 119 throws ClassNotFoundException, IOException { 120 serializedForm = SerializedForm.deserialize(s); 121 } 122 123 private Object readResolve() { 124 return new Result(serializedForm); 125 } 126 127 @RunListener.ThreadSafe 128 private class Listener extends RunListener { 129 @Override 130 public void testRunStarted(Description description) throws Exception { 131 startTime.set(System.currentTimeMillis()); 132 } 133 134 @Override 135 public void testRunFinished(Result result) throws Exception { 136 long endTime = System.currentTimeMillis(); 137 runTime.addAndGet(endTime - startTime.get()); 138 } 139 140 @Override 141 public void testFinished(Description description) throws Exception { 142 count.getAndIncrement(); 143 } 144 145 @Override 146 public void testFailure(Failure failure) throws Exception { 147 failures.add(failure); 148 } 149 150 @Override 151 public void testIgnored(Description description) throws Exception { 152 ignoreCount.getAndIncrement(); 153 } 154 155 @Override 156 public void testAssumptionFailure(Failure failure) { 157 assumptionFailureCount.getAndIncrement(); 158 } 159 } 160 161 /** 162 * Internal use only. 163 */ 164 public RunListener createListener() { 165 return new Listener(); 166 } 167 168 /** 169 * Represents the serialized output of {@code Result}. The fields on this 170 * class match the files that {@code Result} had in JUnit 4.11. 171 */ 172 private static class SerializedForm implements Serializable { 173 private static final long serialVersionUID = 1L; 174 private final AtomicInteger fCount; 175 private final AtomicInteger fIgnoreCount; 176 private final AtomicInteger assumptionFailureCount; 177 private final List<Failure> fFailures; 178 private final long fRunTime; 179 private final long fStartTime; 180 181 public SerializedForm(Result result) { 182 fCount = result.count; 183 fIgnoreCount = result.ignoreCount; 184 assumptionFailureCount = result.assumptionFailureCount; 185 fFailures = Collections.synchronizedList(new ArrayList<Failure>(result.failures)); 186 fRunTime = result.runTime.longValue(); 187 fStartTime = result.startTime.longValue(); 188 } 189 190 @SuppressWarnings("unchecked") 191 private SerializedForm(ObjectInputStream.GetField fields) throws IOException { 192 fCount = (AtomicInteger) fields.get("fCount", null); 193 fIgnoreCount = (AtomicInteger) fields.get("fIgnoreCount", null); 194 assumptionFailureCount = (AtomicInteger) fields.get("assumptionFailureCount", null); 195 fFailures = (List<Failure>) fields.get("fFailures", null); 196 fRunTime = fields.get("fRunTime", 0L); 197 fStartTime = fields.get("fStartTime", 0L); 198 } 199 200 public void serialize(ObjectOutputStream s) throws IOException { 201 ObjectOutputStream.PutField fields = s.putFields(); 202 fields.put("fCount", fCount); 203 fields.put("fIgnoreCount", fIgnoreCount); 204 fields.put("fFailures", fFailures); 205 fields.put("fRunTime", fRunTime); 206 fields.put("fStartTime", fStartTime); 207 fields.put("assumptionFailureCount", assumptionFailureCount); 208 s.writeFields(); 209 } 210 211 public static SerializedForm deserialize(ObjectInputStream s) 212 throws ClassNotFoundException, IOException { 213 ObjectInputStream.GetField fields = s.readFields(); 214 return new SerializedForm(fields); 215 } 216 } 217}