/* * Copyright 2019 Qameta Software OÜ * * 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 io.qameta.allure.spock; import io.qameta.allure.Allure; import io.qameta.allure.AllureLifecycle; import io.qameta.allure.aspects.AttachmentsAspects; import io.qameta.allure.aspects.StepsAspects; import io.qameta.allure.model.Label; import io.qameta.allure.model.Link; import io.qameta.allure.model.Parameter; import io.qameta.allure.model.Stage; import io.qameta.allure.model.Status; import io.qameta.allure.model.StatusDetails; import io.qameta.allure.model.StepResult; import io.qameta.allure.model.TestResult; import io.qameta.allure.spock.samples.BrokenTest; import io.qameta.allure.spock.samples.DataDrivenTest; import io.qameta.allure.spock.samples.FailedTest; import io.qameta.allure.spock.samples.OneTest; import io.qameta.allure.spock.samples.ParametersTest; import io.qameta.allure.spock.samples.TestWithAnnotations; import io.qameta.allure.spock.samples.TestWithAnnotationsOnClass; import io.qameta.allure.spock.samples.TestWithCustomAnnotations; import io.qameta.allure.spock.samples.TestWithSteps; import io.qameta.allure.test.AllureResults; import io.qameta.allure.test.AllureResultsWriterStub; import org.junit.jupiter.api.Test; import org.junit.runner.notification.RunNotifier; import org.spockframework.runtime.JUnitDescriptionGenerator; import org.spockframework.runtime.RunContext; import org.spockframework.runtime.SpecInfoBuilder; import org.spockframework.runtime.model.SpecInfo; import java.time.Instant; import java.util.Optional; import java.util.function.Predicate; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.tuple; /** * @author charlie (Dmitry Baev). */ @SuppressWarnings("unchecked") class AllureSpockTest { @Test void shouldStoreTestsInformation() { final AllureResults results = run(OneTest.class); assertThat(results.getTestResults()) .hasSize(1); } @Test void shouldSetTestStart() { final long before = Instant.now().toEpochMilli(); final AllureResults results = run(OneTest.class); final long after = Instant.now().toEpochMilli(); assertThat(results.getTestResults()) .extracting(TestResult::getStart) .allMatch(v -> v >= before && v <= after); } @Test void shouldSetTestStop() { final long before = Instant.now().toEpochMilli(); final AllureResults results = run(OneTest.class); final long after = Instant.now().toEpochMilli(); assertThat(results.getTestResults()) .extracting(TestResult::getStop) .allMatch(v -> v >= before && v <= after); } @Test void shouldSetTestFullName() { final AllureResults results = run(OneTest.class); assertThat(results.getTestResults()) .extracting(TestResult::getFullName) .containsExactly("io.qameta.allure.spock.samples.OneTest.Simple Test"); } @Test void shouldSetStageFinished() { final AllureResults results = run(OneTest.class); assertThat(results.getTestResults()) .extracting(TestResult::getStage) .containsExactly(Stage.FINISHED); } @Test void shouldProcessFailedTest() { final AllureResults results = run(FailedTest.class); assertThat(results.getTestResults()) .extracting(TestResult::getStatus) .containsExactly(Status.FAILED); } @Test void shouldProcessBrokenTest() { final AllureResults results = run(BrokenTest.class); assertThat(results.getTestResults()) .extracting(TestResult::getStatus) .containsExactly(Status.BROKEN); } @Test void shouldAddStepsToTest() { final AllureResults results = run(TestWithSteps.class); assertThat(results.getTestResults()) .flatExtracting(TestResult::getSteps) .extracting(StepResult::getName) .containsExactly("step1", "step2", "step3"); } @Test void shouldProcessMethodAnnotations() { final AllureResults results = run(TestWithAnnotations.class); assertThat(results.getTestResults()) .hasSize(1) .flatExtracting(TestResult::getLabels) .extracting(Label::getValue) .contains( "epic1", "epic2", "epic3", "feature1", "feature2", "feature3", "story1", "story2", "story3", "some-owner" ); } @Test void shouldProcessClassAnnotations() { final AllureResults results = run(TestWithAnnotationsOnClass.class); assertThat(results.getTestResults()) .hasSize(1) .flatExtracting(TestResult::getLabels) .extracting(Label::getValue) .contains( "epic1", "epic2", "epic3", "feature1", "feature2", "feature3", "story1", "story2", "story3", "some-owner" ); } @Test void shouldProcessCustomAnnotations() { final AllureResults results = run(TestWithCustomAnnotations.class); assertThat(results.getTestResults()) .hasSize(1) .flatExtracting(TestResult::getLabels) .extracting(Label::getValue) .contains( "epic", "feature", "story", "AS-1", "XRT-1" ); } @Test void shouldProcessFlakyAnnotation() { final AllureResults results = run(TestWithAnnotations.class); assertThat(results.getTestResults()) .filteredOn(flakyPredicate()) .hasSize(1); } @Test void shouldProcessMutedAnnotation() { final AllureResults results = run(TestWithAnnotations.class); assertThat(results.getTestResults()) .filteredOn(mutedPredicate()) .hasSize(1); } @Test void shouldSetDisplayName() { final AllureResults results = run(OneTest.class); assertThat(results.getTestResults()) .extracting(TestResult::getName) .containsExactly("Simple Test"); } @Test void shouldSetLinks() { final AllureResults results = run(FailedTest.class); assertThat(results.getTestResults()) .flatExtracting(TestResult::getLinks) .extracting(Link::getName) .containsExactlyInAnyOrder("link-1", "link-2", "issue-1", "issue-2", "tms-1", "tms-2"); } @Test void shouldSetParameters() { final AllureResults results = run(ParametersTest.class); assertThat(results.getTestResults()) .flatExtracting(TestResult::getParameters) .extracting(Parameter::getName, Parameter::getValue) .containsExactlyInAnyOrder( tuple("a", "1"), tuple("b", "3"), tuple("c", "3") ); } @Test void shouldSupportDataDrivenTests() { final AllureResults results = run(DataDrivenTest.class); assertThat(results.getTestResults()) .hasSize(3); } protected AllureResults run(final Class<?> clazz) { final AllureResultsWriterStub results = new AllureResultsWriterStub(); final AllureLifecycle lifecycle = new AllureLifecycle(results); final RunNotifier notifier = new RunNotifier(); final SpecInfo spec = new SpecInfoBuilder(clazz).build(); spec.addListener(new AllureSpock(lifecycle)); new JUnitDescriptionGenerator(spec).describeSpecMethods(); new JUnitDescriptionGenerator(spec).describeSpec(); final AllureLifecycle cached = Allure.getLifecycle(); try { Allure.setLifecycle(lifecycle); StepsAspects.setLifecycle(lifecycle); AttachmentsAspects.setLifecycle(lifecycle); RunContext.get().createSpecRunner(spec, notifier).run(); } catch (Exception e) { throw new RuntimeException("could not execute sample", e); } finally { Allure.setLifecycle(cached); StepsAspects.setLifecycle(cached); AttachmentsAspects.setLifecycle(cached); } return results; } private static Predicate<TestResult> mutedPredicate() { return testResult -> Optional.of(testResult) .map(TestResult::getStatusDetails) .map(StatusDetails::isMuted) .filter(m -> m) .isPresent(); } private static Predicate<TestResult> flakyPredicate() { return testResult -> Optional.of(testResult) .map(TestResult::getStatusDetails) .map(StatusDetails::isFlaky) .filter(m -> m) .isPresent(); } }