How to send TestNG DefaultSuite results after retryAnalyzer to Maven Surefire Plugin - unit-testing

I did search a lot and this is the closest answer that I got but does not solve my problem. TestNG retrying failed tests doesn't output the correct test results
But I need the above problem to extend from TestNG onto Maven. Please help.
My Project stack: TestNG, Maven surefire plugin, Maven. I am running the tests from command line - "mvn clean compile test". I am using a retryanalyzer to re-run the failed tests, that are passing the second time. I have been able to use a CustomListener to update the results stored in the TestNG's testcontext (based on solutions in stackoverflow). This was confirmed when I ran the tests as TestNG suite.
But when I run "mvn clean compile test", all the retries are counted as separate tests and build always fails. How do I make TestNG send only the final Suite results to Maven Surefire plugin ?
TESTNG EXECUTION:
============================================
DefaultTest
Total tests run: 4, Failures: 2, Skips: 0
============================================
============================================
DefaultSuite
Total tests run: 2, Failures: 0, Skips: 0
============================================
MAVEN EXECUTION:
Tests run: 4, Failures: 2, Errors: 0, Skipped: 0, Time elapsed: 0.292 sec <<< FAILURE!
Results :
Failed tests:
test1(foo.TestClass1)
test1(foo.TestClass1)
Tests run: 4, Failures: 2, Errors: 0, Skipped: 0
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
The build passed because of the retry. How do I reflect the TestNG retry Suite results onto Maven ?

Finally got it. I use this code:
ListenerApadter:
public class MyTestListenerAdapter extends TestListenerAdapter {
#Override
public void onTestFailure(ITestResult result) {
if (result.getMethod().getRetryAnalyzer() != null) {
MyRetryAnalyzer retryAnalyzer = (MyRetryAnalyzer)result.getMethod().getRetryAnalyzer();
if(retryAnalyzer.isRetryAvailable()) {
result.setStatus(ITestResult.SKIP);
} else {
result.setStatus(ITestResult.FAILURE);
}
Reporter.setCurrentTestResult(result);
}
}
#Overrride
public void onFinish(ITestContext context) {
Iterator<ITestResult> failedTestCases =context.getFailedTests().getAllResults().iterator();
while (failedTestCases.hasNext()) {
System.out.println("failedTestCases");
ITestResult failedTestCase = failedTestCases.next();
ITestNGMethod method = failedTestCase.getMethod();
if (context.getFailedTests().getResults(method).size() > 1) {
System.out.println("failed test case remove as dup:" + failedTestCase.getTestClass().toString());
failedTestCases.remove();
} else {
if (context.getPassedTests().getResults(method).size() > 0) {
System.out.println("failed test case remove as pass retry:" + failedTestCase.getTestClass().toString());
failedTestCases.remove();
}
}
}
}
}
RetryAnalizer:
public class MyRetryAnalyzer implements IRetryAnalyzer {
private static int MAX_RETRY_COUNT = 3;
AtomicInteger count = new AtomicInteger(MAX_RETRY_COUNT);
public boolean isRetryAvailable() {
return (count.intValue() > 0);
}
#Override
public boolean retry(ITestResult result) {
boolean retry = false;
if (isRetryAvailable()) {
System.out.println("Going to retry test case: " + result.getMethod() + ", " + (MAX_RETRY_COUNT - count.intValue() + 1) + " out of " + MAX_RETRY_COUNT);
retry = true;
count.decrementAndGet();
}
return retry;
}
}
POM.xml -> Surefire Configuration:
This is where you should configure "overwrite" surefire listener wich has their own counters.
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.18.1</version>
<configuration>
<suiteXmlFiles><suiteXmlFile>${basedir}/testng.xml</suiteXmlFile></suiteXmlFiles>
<properties>
<property>
<name>listener</name>
<value>Utils.MyTestListenerAdapter,Utils.MyRetryAnalizer</value>
</property>
</properties>

Some suit info is incorrect, but maven surefire works properly
maven-surefire-plugin 2.16
testng 6.8.8
// ===== InvokedMethodListener =====
import org.testng.IInvokedMethod;
import org.testng.IInvokedMethodListener;
import org.testng.ITestResult;
public class InvokedMethodListener implements IInvokedMethodListener {
#Override
public void beforeInvocation(IInvokedMethod method, ITestResult testResult) {
}
#Override
public void afterInvocation(IInvokedMethod method, ITestResult testResult) {
RetryAnalyzer retryAnalyzer = (RetryAnalyzer)testResult.getMethod().getRetryAnalyzer();
if (retryAnalyzer == null || retryAnalyzer.isFailed()) {
return;
}
if (testResult.getStatus() == ITestResult.FAILURE) {
testResult.setStatus(ITestResult.SUCCESS);
}
}
}
// ===== RetryAnalyzer =====
import org.testng.IRetryAnalyzer;
import org.testng.ITestResult;
import org.testng.Reporter;
public class RetryAnalyzer implements IRetryAnalyzer {
private int count = 0;
private int maxCount = 2;
#Override
public boolean retry(ITestResult result) {
if (!result.isSuccess()) {
if (count < maxCount) {
count++;
return true;
}
}
return false;
}
public boolean isFailed() {
return count >= maxCount;
}
}
// ===== BaseTest =====
#Listeners({ ..InvokedMethodListener.class })
public abstract class BaseTest {
...
#BeforeSuite(alwaysRun = true)
public void beforeSuite(ITestContext context) {
for (ITestNGMethod method : context.getAllTestMethods()) {
method.setRetryAnalyzer(new RetryAnalyzer());
}
}
}

Related

android unit test, how to test the activity crated by context.startActivity(intent)

Having an activity which has some functions need to be coverage tested.
class HandlerActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle ) {
System.out.println("enter HandlerActivity.onCreate()")
doSomething(intent)
}
}
//////////////
#RunWith(RobolectricTestRunner::class)
class HandlerActivityTest {
#Test
fun test_activity() {
val conextSpy = spyk(ApplicationProvider.getApplicationContext())
var testEx: Throwable? = null
try {
val intent = Intent(this, HandlerActivity::class.java)
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
conextSpy.startActivity(intent)
Shadows.shadowOf(Looper.getMainLooper()).idle()
} catch (ex: Throwable) {
testEx = ex
}
junit.framework.Assert.assertNull(testEx)
io.mockk.verify { contextSpy.startActivity(any()) }
}
The test passed, but the HandlerActivity.onCreate() is not called.
How to unit test a onCreate() of an activity?

When I test my quarkus resource endpoint my main service is getting called

So Basically i have a ResourceTest.class and MockService.class under src/test/java.
ResourceFile is like the following
#QuarkusTest
public class ResourceTest {
#Test
public void testFetch() {
given().queryParam("fromTime", 0)
.queryParam("toTime", 0)
.queryParam("skip", 0)
.queryParam("limit", 5)
.queryParam("search", "")
.port(80)
.when().get("http://localhost/fetch")
.then()
.statusCode(200)
.body( is(CompletableFuture.completedFuture(BaseResponse.create(true, "Fetched.", Utils.populatePages(list,0,5,5)))));
}
}
My Mock Service file looks like this..
#Mock
#ApplicationScoped
public class MockService extends Service {
#Override
public CompletableFuture<BaseResponse> fetch(String encounterId, String providerId, String patientId, long fromTime, long toTime, int skip, int limit, String search, Boolean isResolve) {
return CompletableFuture.completedFuture(BaseResponse.create
(true, "Fetched.", Utils.populatePages(list, 0, 5, 5)));
}
}
Whenever I run my testFetch() method, My main service file gets called instead of MockServicefile..
What should i do to make my mockService get called..?
You should prefer per-test mocks injection over #Mock bean replacement for scoped CDI beans when using io.quarkus.test.junit.QuarkusMock.
Quarkus provides out of the box integration with Mockito allowing to mock CDI scoped beans with the io.quarkus.test.junit.mockito.#InjectMock annotation.
#QuarkusTest
public class ResourceTest {
#InjectMock
MockService mockService;
#BeforeEach
public void setup() {
// Here you can override the wide mock bean behavior per-each test
Mockito.when(mockService.fetch(any(),any(),any(),any(),any(),any(),any(),any(),any())).thenReturn(CompletableFuture.completedFuture(BaseResponse.create
(true, "Fetched.", Utils.populatePages(list, 0, 5, 5))));
}
#Test
public void testFetch() {
given().queryParam("fromTime", 0)
.queryParam("toTime", 0)
.queryParam("skip", 0)
.queryParam("limit", 5)
.queryParam("search", "")
.port(80)
.when().get("http://localhost/fetch")
.then()
.statusCode(200)
.body( is(CompletableFuture.completedFuture(BaseResponse.create(true, "Fetched.", Utils.populatePages(list,0,5,5)))));
}
//#Mock: No #Mock annotation needed
#ApplicationScoped
public class MockService extends Service {
#Override
public CompletableFuture<BaseResponse> fetch(String encounterId, String providerId, String patientId, long fromTime, long toTime, int skip, int limit, String search, Boolean isResolve) {
// Here you can have your wide-test methods mock implementations
return CompletableFuture.completedFuture(BaseResponse.create
(true, "Fetched.", Utils.populatePages(list, 0, 5, 5)));
}
}
}
Don't forget to include the quarkus-junit5-mockito integration artifact:
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-junit5-mockito</artifactId>
<scope>test</scope>
</dependency>

Jacoco shows coverage 0.0 when running the gradle task but shows correct when run from Intellij

I am using Jacoco plugin to calculate the code coverage for spring boot application. The Jacoco configuration from the build.gradle looks like this:
jacocoTestReport {
reports {
xml.enabled false
csv.enabled false
html.destination file("${buildDir}/jacocoHtml")
}
afterEvaluate {
classDirectories = files(classDirectories.files.collect {
fileTree(dir: it,
exclude: ['**/models/**',
'**/config/**',
'**/constants/**',
'**/Application.class'])
})
}
}
and
jacocoTestCoverageVerification {
violationRules {
rule {
element = 'PACKAGE'
excludes = ['some packages']
limit {
counter = 'BRANCH'
minimum = 0.7
}
}
}
}
When I run the coverage from the IntelliJ then it shows the correct result but when I run it with gradlew clean buils, it fails with coverage 0.0.
I have written an example class and here are the jacoco report snapshots-
report:
class:
And the test I wrote for the SomeClass is
public class SomeClassTest {
private SomeClass someClass;
#Before
public void setUp() throws Exception {
someClass = new SomeClass(12, 23);
}
#Test
public void shouldSumTwoValues() {
assertThat(someClass.sum()).isEqualTo(35);
}
}
Can someone please help me with this?
Given src/main/java/SomeClass.java
class SomeClass {
private Integer value1;
private Integer value2;
SomeClass(Integer value1, Integer value2) {
this.value1 = value1;
this.value2 = value2;
}
Integer sum() {
return value1 + value2;
}
}
src/test/java/SomeClassTest.java
import org.junit.*;
import static org.junit.Assert.*;
public class SomeClassTest {
private SomeClass someClass;
#Before
public void setUp() throws Exception {
someClass = new SomeClass(12, 23);
}
#Test
public void shouldSumTwoValues() {
assertEquals(35, (int) someClass.sum());
}
}
and build.gradle
apply plugin: "java"
apply plugin: "jacoco"
dependencies {
testCompile "junit:junit:4.12"
}
repositories {
mavenCentral()
}
execution of gradle test jacocoTestReport produces following report in build/reports/jacoco/test/html/index.html
Addition to build.gradle of
jacocoTestReport {
reports {
xml.enabled false
csv.enabled false
html.destination file("${buildDir}/jacocoHtml")
}
afterEvaluate {
classDirectories = files(classDirectories.files.collect {
fileTree(dir: it,
exclude: ['**/models/**',
'**/config/**',
'**/constants/**',
'**/Application.class'])
})
}
}
jacocoTestCoverageVerification {
violationRules {
rule {
element = 'PACKAGE'
excludes = ['some packages']
limit {
counter = 'BRANCH'
minimum = 0.7
}
}
}
}
doesn't change result/report, except of change of directory with report on build/jacocoHtml.
In my case I discovered that it is due to the fact that I set minimum = 1. When I change it to 0.9 all of the sudden it works

Ignore test to be executed locally in spring boot

I need to disable execution of one unit test on local environment. We run unit tests in local with local-test profile
-Dspring.profiles.active=local-test
I need to execute my test at all profiles except local-test How can I achieve this?
Here is my test, if I put value = "!local-test" it does not work
#IfProfileValue(name = "spring.profiles.active", value = "local-test")
#RunWith(SpringRunner.class)
public class EnvironmentTests {
#Test
public void TestNightTimeFormatCorrect() {
throw new RuntimeException("test exception");
}
}
I found a solution, hope it will be useful for somebody.
In this case TestNightTimeFormatCorrect will be executed every time when there is no local-test profile. It will be alse executed when no profile is set.
#RunWith(SpringJUnit4ClassRunner.class)
#ProfileValueSourceConfiguration(EnvironmentTests.ProfileProfileValueSource.class)
#IfProfileValue(name = "local-test", value = "false")
public class EnvironmentTests {
#Test
public void TestNightTimeFormatCorrect() {
throw new RuntimeException("test exception");
}
public static class ProfileProfileValueSource implements ProfileValueSource
{
#Override
public String get(String string)
{
final String systemProfiles = System.getProperty("spring.profiles.active", System.getProperty("SPRING_PROFILES_ACTIVE", ""));
final String[] profiles = systemProfiles.split(",");
return Arrays.asList(profiles).contains(string) ? "true" : "false";
}
}
}

Interceptors doesn't work in Unit tests

I am get Interceptors working on the application server. I have annotated EJB:
#Stateless
#Named("accountsEJB")
public class AccountsEJB {
#PersistenceContext(unitName = "weducationPU")
private EntityManager em;
// . . . other methods
#WithLog
#Restricted(allowedRoles = {}) // Allowed only for admin
public Account save(Account item) {
if (item.getId() == 0) {
em.persist(item);
return item;
} else {
return em.merge(item);
}
}
#WithLog
#Restricted(allowedRoles = {}) // Allowed only for admin
public void delete(final Account item) {
Account a = em.find(Account.class, item.getId());
if (null != a) {
em.remove(a);
}
}
}
Empty list of roles means, that It's allowed only for role admin.
Here the unit test file for this EJB
public class AccountsEJBTest {
private static EJBContainer container;
private static AccountsEJB ejb;
#BeforeClass
public static void setUpClass() {
try {
Map<String, Object> properties = new HashMap<>();
properties.put(EJBContainer.MODULES, new File("target/classes"));
properties.put("org.glassfish.ejb.embedded.glassfish.installation.root", "glassfish");
properties.put(EJBContainer.APP_NAME, "weducation");
container = EJBContainer.createEJBContainer(properties);
ejb = (AccountsEJB) container.getContext().lookup("java:global/weducation/classes/AccountsEJB");
System.out.println("AccountsEJBTest running...");
} catch (NamingException e) {
fail("Container init error: " + e.getMessage());
}
}
#AfterClass
public static void tearDownClass() {
if (null != container) {
container.close();
}
System.out.println("AccountsEJBTest finished");
}
private boolean equals(Account source, Account result) {
if (!source.getFullName().contentEquals(result.getFullName())) return false;
if (!source.getLogin().contentEquals(result.getLogin())) return false;
return source.getRole() == result.getRole();
}
#Test
public void testOperations() {
try {
System.out.println("-->testOperations()");
Account testAccount = new Account();
testAccount.setFullName("Test Account");
testAccount.setLogin("test");
testAccount.setPassword("test");
testAccount.setConfirm("test");
testAccount.updatePassword();
testAccount.setRole(AccountRole.DEPOT);
Account savedAccount = ejb.save(testAccount);
assertTrue(equals(testAccount, savedAccount));
savedAccount.setFullName("Still Test Account");
savedAccount.setLogin("test1");
testAccount = ejb.save(savedAccount);
assertTrue(equals(testAccount, savedAccount));
testAccount.setPassword("testpwd");
testAccount.setConfirm("testpwd");
testAccount.updatePassword();
savedAccount = ejb.save(testAccount);
assertTrue(equals(testAccount, savedAccount));
ejb.delete(savedAccount);
} catch (Exception e) {
fail("Exception class " + e.getClass().getName() + " with message " + e.getMessage());
}
}
}
And this test working. I think, that is not correct, because there is no user with admin role logged in. But why this behavior happing?
UPDATED.
#Restricted interface:
#Inherited
#InterceptorBinding
#Target({METHOD, TYPE})
#Retention(RUNTIME)
public #interface Restricted {
#Nonbinding
AccountRole[] allowedRoles();
}
SecurityInterceptor class
#Interceptor
#Restricted(allowedRoles = {})
public class SecurityInterceptor implements Serializable {
#Inject
private transient SessionMB session;
#AroundInvoke
public Object checkSecurity(InvocationContext context) throws Exception {
//System.out.println("Security checker started.");
if ((session == null) || (session.getUser() == null)) {
throw new SecurityException("Can't get user info");
}
// Allow all to admin
if (session.isAdmin()) {
//System.out.println("It's admin.");
return context.proceed();
}
// walk non administrator roles
for (AccountRole r : getAllowedRoles(context.getMethod())) {
// if match - accept method invocation
if (session.getUser().getRole() == r) {
//System.out.println("It's " + r.getDescription());
return context.proceed();
}
}
throw new SecurityException(session.getUser().getFullName()
+ " has no souch privilegies ");
}
private AccountRole[] getAllowedRoles(Method m) {
if (null == m) {
throw new IllegalArgumentException("Method is null!");
}
// Walk all method annotations
for (Annotation a : m.getAnnotations()) {
if (a instanceof Restricted) {
return ((Restricted) a).allowedRoles();
}
}
// Now - walk all class annotations
if (null != m.getDeclaringClass()) {
for (Annotation a : m.getDeclaringClass().getAnnotations()) {
if (a instanceof Restricted) {
return ((Restricted) a).allowedRoles();
}
}
}
// if no annotaion found
throw new RuntimeException("Annotation #Restricted not found at method "
+ m.getName() + " or it's class.");
}
}
The beans.xml is placed in WEB-INF folder and looks like
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd"
bean-discovery-mode="annotated">
<interceptors>
<class>ru.edu.pgtk.weducation.interceptors.LogInterceptor</class>
<class>ru.edu.pgtk.weducation.interceptors.SecurityInterceptor</class>
</interceptors>
</beans>
Can someone help me to know:
How to get Interceptors working in Unit tests?
How to start authorized session in Unit tests (log in as admin, for example)?
How to test such operations as creation and deleting account with the different tests (one test for creating, one for deleting)? Is it correct - to test all operations in one test?
Thank you for your time and your questions.