-
Notifications
You must be signed in to change notification settings - Fork 100
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Log Fixture Monkey seed on test failure (#1010)
- Loading branch information
Showing
4 changed files
with
268 additions
and
0 deletions.
There are no files selected for viewing
32 changes: 32 additions & 0 deletions
32
...unit-jupiter/src/main/java/com/navercorp/fixturemonkey/junit/jupiter/annotation/Seed.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
/* | ||
* Fixture Monkey | ||
* | ||
* Copyright (c) 2021-present NAVER Corp. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
package com.navercorp.fixturemonkey.junit.jupiter.annotation; | ||
|
||
import java.lang.annotation.ElementType; | ||
import java.lang.annotation.Retention; | ||
import java.lang.annotation.RetentionPolicy; | ||
import java.lang.annotation.Target; | ||
|
||
@Retention(RetentionPolicy.RUNTIME) | ||
@Target({ElementType.METHOD}) | ||
public @interface Seed { | ||
/** | ||
* This value is used to set the seed for generating random numbers. | ||
*/ | ||
long value() default 0L; | ||
} |
71 changes: 71 additions & 0 deletions
71
.../java/com/navercorp/fixturemonkey/junit/jupiter/extension/FixtureMonkeySeedExtension.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
/* | ||
* Fixture Monkey | ||
* | ||
* Copyright (c) 2021-present NAVER Corp. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
package com.navercorp.fixturemonkey.junit.jupiter.extension; | ||
|
||
import java.lang.reflect.Method; | ||
|
||
import org.junit.jupiter.api.extension.AfterTestExecutionCallback; | ||
import org.junit.jupiter.api.extension.BeforeTestExecutionCallback; | ||
import org.junit.jupiter.api.extension.ExtensionContext; | ||
import org.slf4j.Logger; | ||
import org.slf4j.LoggerFactory; | ||
|
||
import com.navercorp.fixturemonkey.api.random.Randoms; | ||
import com.navercorp.fixturemonkey.junit.jupiter.annotation.Seed; | ||
|
||
public final class FixtureMonkeySeedExtension implements BeforeTestExecutionCallback, AfterTestExecutionCallback { | ||
private static final ThreadLocal<Long> SEED_HOLDER = new ThreadLocal<>(); | ||
|
||
private static final Logger LOGGER = LoggerFactory.getLogger(FixtureMonkeySeedExtension.class); | ||
|
||
@Override | ||
public void beforeTestExecution(ExtensionContext context) throws Exception { | ||
Seed seed = context.getRequiredTestMethod().getAnnotation(Seed.class); | ||
if (seed != null) { | ||
setSeed(seed.value()); | ||
} | ||
} | ||
|
||
/** | ||
* Logs the seed used for the test if the test fails. | ||
* This method is called after a test method has executed. | ||
* If the test failed, it logs the seed used for the test. | ||
**/ | ||
@Override | ||
public void afterTestExecution(ExtensionContext context) throws Exception { | ||
if (context.getExecutionException().isPresent()) { | ||
logSeedIfTestFailed(context); | ||
} | ||
} | ||
|
||
/** | ||
* Sets the seed for generating random numbers. | ||
**/ | ||
private void setSeed(long seed) { | ||
SEED_HOLDER.set(Randoms.create(String.valueOf(seed)).nextLong()); | ||
} | ||
|
||
/** | ||
* Logs the seed if the test failed. | ||
* This method logs the seed value when a test method execution fails. | ||
**/ | ||
private void logSeedIfTestFailed(ExtensionContext context) { | ||
Method testMethod = context.getRequiredTestMethod(); | ||
LOGGER.error(String.format("Test Method [%s] failed with seed: %d", testMethod.getName(), SEED_HOLDER.get())); | ||
} | ||
} |
161 changes: 161 additions & 0 deletions
161
...a/com/navercorp/fixturemonkey/junit/jupiter/extension/FixtureMonkeySeedExtensionTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,161 @@ | ||
/* | ||
* Fixture Monkey | ||
* | ||
* Copyright (c) 2021-present NAVER Corp. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
package com.navercorp.fixturemonkey.junit.jupiter.extension; | ||
|
||
import static org.assertj.core.api.BDDAssertions.then; | ||
import static org.junit.jupiter.api.Assertions.assertAll; | ||
import static org.junit.jupiter.api.Assertions.assertEquals; | ||
import static org.junit.jupiter.api.Assertions.assertNotNull; | ||
import static org.junit.jupiter.api.Assertions.assertTrue; | ||
|
||
import java.util.Collections; | ||
import java.util.HashSet; | ||
import java.util.List; | ||
import java.util.Set; | ||
|
||
import javax.validation.constraints.NotBlank; | ||
import javax.validation.constraints.NotNull; | ||
|
||
import org.junit.jupiter.api.AfterEach; | ||
import org.junit.jupiter.api.BeforeAll; | ||
import org.junit.jupiter.api.RepeatedTest; | ||
import org.junit.jupiter.api.Test; | ||
import org.junit.jupiter.api.extension.ExtendWith; | ||
import org.slf4j.Logger; | ||
import org.slf4j.LoggerFactory; | ||
|
||
import ch.qos.logback.classic.Level; | ||
import ch.qos.logback.classic.LoggerContext; | ||
import ch.qos.logback.classic.spi.ILoggingEvent; | ||
import ch.qos.logback.core.read.ListAppender; | ||
import lombok.Data; | ||
|
||
import com.navercorp.fixturemonkey.FixtureMonkey; | ||
import com.navercorp.fixturemonkey.api.type.TypeReference; | ||
import com.navercorp.fixturemonkey.junit.jupiter.annotation.Seed; | ||
|
||
@ExtendWith(FixtureMonkeySeedExtension.class) | ||
class FixtureMonkeySeedExtensionTest { | ||
private static final FixtureMonkey SUT = FixtureMonkey.create(); | ||
private static ListAppender<ILoggingEvent> EVENT_APPENDER; | ||
|
||
@BeforeAll | ||
static void setup() { | ||
LoggerContext loggerContext = (LoggerContext)LoggerFactory.getILoggerFactory(); | ||
|
||
EVENT_APPENDER = new ListAppender<>(); | ||
EVENT_APPENDER.setContext(loggerContext); | ||
EVENT_APPENDER.start(); | ||
|
||
loggerContext.getLogger(Logger.ROOT_LOGGER_NAME).addAppender(EVENT_APPENDER); | ||
loggerContext.getLogger(Logger.ROOT_LOGGER_NAME).setLevel(Level.ERROR); | ||
|
||
} | ||
|
||
@AfterEach | ||
void tearDown() { | ||
EVENT_APPENDER.list.clear(); | ||
} | ||
|
||
@Seed(1234L) | ||
@Test | ||
void testWithSeed() { | ||
boolean logFound = false; | ||
try { | ||
Product product = SUT.giveMeBuilder(Product.class) | ||
.set("id", 1000L) | ||
.set("productName", "Book") | ||
.sample(); | ||
|
||
assertAll( | ||
() -> assertNotNull(product), | ||
() -> assertEquals(2000L, (long)product.getId()), | ||
() -> assertEquals("Computer", product.getProductName()) | ||
); | ||
} catch (AssertionError e) { | ||
List<ILoggingEvent> logs = EVENT_APPENDER.list; | ||
logFound = logs.stream() | ||
.anyMatch(event -> event.getFormattedMessage() | ||
.contains("Test Method [testWithSeed] failed with seed: ")); | ||
} | ||
assertTrue(logFound, "Expected log message found."); | ||
} | ||
|
||
@Seed(1) | ||
@RepeatedTest(100) | ||
void seedReturnsSame() { | ||
String expected = "섨ꝓ仛禦催ᘓ蓊類౺阹瞻塢飖獾ࠒ⒐፨婵얎⽒竻·俌欕悳잸횑ٻ킐結"; | ||
|
||
String actual = SUT.giveMeOne(String.class); | ||
|
||
then(actual).isEqualTo(expected); | ||
} | ||
|
||
@Seed(1) | ||
@RepeatedTest(100) | ||
void latterValue() { | ||
String expected = "聩ዡ㘇뵥刲禮ᣮ鎊熇捺셾壍Ꜻꌩ垅凗❉償粐믩࠱哠횛"; | ||
SUT.giveMeOne(String.class); | ||
|
||
String actual = SUT.giveMeOne(String.class); | ||
|
||
then(actual).isEqualTo(expected); | ||
} | ||
|
||
@Seed(1) | ||
@RepeatedTest(100) | ||
void containerReturnsSame() { | ||
List<String> expected = Collections.singletonList("仛禦催ᘓ蓊類౺阹瞻塢飖獾ࠒ⒐፨婵얎⽒竻·俌欕悳잸횑ٻ킐結"); | ||
|
||
List<String> actual = SUT.giveMeOne(new TypeReference<List<String>>() { | ||
}); | ||
|
||
then(actual).isEqualTo(expected); | ||
} | ||
|
||
@Seed(1) | ||
@RepeatedTest(100) | ||
void containerMattersOrder() { | ||
Set<String> expected = new HashSet<>(Collections.singletonList("仛禦催ᘓ蓊類౺阹瞻塢飖獾ࠒ⒐፨婵얎⽒竻·俌欕悳잸횑ٻ킐結")); | ||
|
||
Set<String> actual = SUT.giveMeOne(new TypeReference<Set<String>>() { | ||
}); | ||
|
||
then(actual).isEqualTo(expected); | ||
} | ||
|
||
@Seed(1) | ||
@RepeatedTest(100) | ||
void multipleContainerReturnsDiff() { | ||
Set<String> firstSet = SUT.giveMeOne(new TypeReference<Set<String>>() { | ||
}); | ||
|
||
List<String> secondList = SUT.giveMeOne(new TypeReference<List<String>>() { | ||
}); | ||
|
||
then(firstSet).isNotEqualTo(secondList); | ||
} | ||
|
||
@Data | ||
private static class Product { | ||
@NotNull | ||
private Long id; | ||
@NotBlank | ||
private String productName; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters