io.qameta.allure.hamcrest.AllureHamcrestAssert Maven / Gradle / Ivy
Show all versions of allure-hamcrest Show documentation
/*
* Copyright 2021 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.hamcrest;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.AfterReturning;
import io.qameta.allure.Allure;
import io.qameta.allure.AllureLifecycle;
import io.qameta.allure.model.Status;
import io.qameta.allure.model.StepResult;
import io.qameta.allure.util.ObjectUtils;
import org.hamcrest.Matcher;
import org.hamcrest.StringDescription;
import java.util.UUID;
import static io.qameta.allure.util.ResultsUtils.getStatus;
/**
*
* Aspect "interceptor" for automatic logging to the Allure report.
*
*
* This aspect should work for all asserts that are in the Hamcrest library, since they all go through a single method
* to start the comparison.
*
*
* In addition to the standard comparisons that are already in the Hamcrest library, this aspect should work correctly
* with custom matchers if developers correctly implemented the describeMismatch and / or describeMismatchSafely
* methods in the TypeSafeMatcher class.
*
*
* @author a-simeshin (Simeshin Artem)
* @see org.hamcrest.TypeSafeMatcher
*/
@Aspect
@SuppressWarnings("all")
public class AllureHamcrestAssert {
private static InheritableThreadLocal lifecycle = new InheritableThreadLocal() {
@Override
protected AllureLifecycle initialValue() {
return Allure.getLifecycle();
}
};
public static AllureLifecycle getLifecycle() {
return lifecycle.get();
}
@Pointcut("execution(void org.hamcrest.MatcherAssert.**(..))")
public void initAssertThat() {
}
/**
*
* assertThat(String comment, Object actual, Matcher expected) - one and only one central entry point for all
* asserts. Based on this rule, you only need to log a method with three arguments.
*
*
* Even if there is no comment as the first argument, an empty string will be passed as the first argument.
*
*
* For example assertThat(value123.get(), is(equalTo("value123"))) will be proxied to the metod
* assertThat("", value123.get(), is(equalTo("value123")))
*
*
* @param joinPoint - entry point with args and method name
*/
@Before("initAssertThat()")
public void catchAndStartStep(final JoinPoint joinPoint) {
if (joinPoint.getArgs().length == 3) {
final String reason = (String) joinPoint.getArgs()[0];
final String actual = ObjectUtils.toString(joinPoint.getArgs()[1]);
final StringDescription description = new StringDescription();
final String expecting = description.appendText("assert \"")
.appendText(actual)
.appendText("\" ")
.appendDescriptionOf((Matcher) joinPoint.getArgs()[2])
.toString();
getLifecycle().startStep(
UUID.randomUUID().toString(),
new StepResult()
.setName(reason.isEmpty() ? expecting : expecting + " | " + reason)
.setDescription("Hamcrest assert")
.setStatus(Status.PASSED)
);
}
}
@AfterThrowing(pointcut = "initAssertThat()", throwing = "e")
public void stepFailed(final Throwable e) {
getLifecycle().updateStep(s -> s.setStatus(getStatus(e).orElse(Status.BROKEN)));
getLifecycle().stopStep();
}
@AfterReturning(pointcut = "initAssertThat()")
public void stepStop() {
getLifecycle().updateStep(s -> s.setStatus(Status.PASSED));
getLifecycle().stopStep();
}
/**
* For tests only.
*
* @param allure allure lifecycle to set
*/
public static void setLifecycle(final AllureLifecycle allure) {
lifecycle.set(allure);
}
}