2

I have a class that i had to test:

package com.mycompany.openapi.cms.core.support.liquibase;

import liquibase.change.custom.CustomTaskChange;
import liquibase.database.Database;
import liquibase.database.jvm.JdbcConnection;
import liquibase.exception.CustomChangeException;
import liquibase.exception.SetupException;
import liquibase.exception.ValidationErrors;
import liquibase.resource.ResourceAccessor;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.sql.Statement;
import java.util.Set;

public class ApplySqlFileIfExistsChange implements CustomTaskChange {

    private final org.slf4j.Logger logger = LoggerFactory.getLogger(getClass());

    private String file;
    private ResourceAccessor resourceAccessor;

    @Override
    public void execute(Database database) throws CustomChangeException {
        JdbcConnection databaseConnection = (JdbcConnection) database.getConnection();
        try {
            Set<InputStream> files = resourceAccessor.getResourcesAsStream(file);
            if(files != null){
                for (InputStream inputStream : files) {
                    BufferedReader in = new BufferedReader(
                            new InputStreamReader(inputStream));
                    String str;
                    String sql;
                    StringBuilder sqlBuilder = new StringBuilder("");
                    while ((str = in.readLine()) != null) {
                        sqlBuilder.append(str).append(" ");
                    }
                    in.close();
                    sql = sqlBuilder.toString().trim();
                    if(StringUtils.isEmpty(sql)){
                        return;
                    }
                    Statement statement = databaseConnection.createStatement();
                    statement.execute(sql);
                    statement.close();
                }
            }
        } catch (FileNotFoundException e) {
            logger.error(e.getMessage(), e);
        } catch (Exception e) {
            throw new CustomChangeException(e);
        }
    }

    public String getFile() {
        return file;
    }

    public void setFile(String file) {
        this.file = file;
    }

    @Override
    public void setFileOpener(ResourceAccessor resourceAccessor) {
        this.resourceAccessor = resourceAccessor;
    }
}

I had written the test:

package com.mycompany.openapi.cms.core.support.liquibase;

import com.google.common.collect.Sets;
import liquibase.database.Database;
import liquibase.database.jvm.JdbcConnection;
import liquibase.resource.ResourceAccessor;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.sql.Statement;

import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.verify;
import static org.powermock.api.mockito.PowerMockito.*;

@RunWith(PowerMockRunner.class)
@PrepareForTest({LoggerFactory.class})
public class TestApplySqlFileIfExistsChange {

    @InjectMocks
    ApplySqlFileIfExistsChange applySqlFileIfExistsChange;

    @Mock
    private ResourceAccessor resourceAccessor;

    @Mock
    private JdbcConnection jdbcConnection;

    @Mock
    private Database database;

    @Mock
    Statement statement;

    @BeforeClass
    public static void setUpClass() {
        mockStatic(LoggerFactory.class);
        when(LoggerFactory.getLogger(ApplySqlFileIfExistsChange.class)).thenReturn(mock(Logger.class));
    }

    @Before
    public void setUp() throws Exception {
        when(database.getConnection()).thenReturn(jdbcConnection);

        InputStream inp1, inp2;
        inp1 = new ByteArrayInputStream("FirstTestQuery".getBytes(StandardCharsets.UTF_8));
        inp2 = new ByteArrayInputStream("SecondTestQuery".getBytes(StandardCharsets.UTF_8));

        when(resourceAccessor.getResourcesAsStream(anyString())).thenReturn(Sets.newHashSet(inp1, inp2));
        when(jdbcConnection.createStatement()).thenReturn(statement);
    }

    @Test
    public void execute() throws Exception {
        applySqlFileIfExistsChange.execute(database);
        verify(statement).execute("FirstTestQuery");
        verify(statement).execute("SecondTestQuery");
    }

}

Problem is that test above passed in my IDE, but when i make push in repository TeamCity build failed on my test. I can't undestand why, because code are same in both places. Here is stack trace in TeamCity:

java.lang.IllegalStateException: Failed to transform class with name org.slf4j.LoggerFactory. Reason: java.io.IOException: invalid constant type: 15
    at org.powermock.core.classloader.MockClassLoader.loadMockClass(MockClassLoader.java:267)
    at org.powermock.core.classloader.MockClassLoader.loadModifiedClass(MockClassLoader.java:180)
    at org.powermock.core.classloader.DeferSupportingClassLoader.loadClass(DeferSupportingClassLoader.java:70)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
    at java.lang.Class.forName0(Native Method)
    at java.lang.Class.forName(Class.java:348)
    at sun.reflect.generics.factory.CoreReflectionFactory.makeNamedType(CoreReflectionFactory.java:114)
    at sun.reflect.generics.visitor.Reifier.visitClassTypeSignature(Reifier.java:125)
    at sun.reflect.generics.tree.ClassTypeSignature.accept(ClassTypeSignature.java:49)
    at sun.reflect.annotation.AnnotationParser.parseSig(AnnotationParser.java:439)
    at sun.reflect.annotation.AnnotationParser.parseClassValue(AnnotationParser.java:420)
    at sun.reflect.annotation.AnnotationParser.parseClassArray(AnnotationParser.java:724)
    at sun.reflect.annotation.AnnotationParser.parseArray(AnnotationParser.java:531)
    at sun.reflect.annotation.AnnotationParser.parseMemberValue(AnnotationParser.java:355)
    at sun.reflect.annotation.AnnotationParser.parseAnnotation2(AnnotationParser.java:286)
    at sun.reflect.annotation.AnnotationParser.parseAnnotations2(AnnotationParser.java:120)
    at sun.reflect.annotation.AnnotationParser.parseAnnotations(AnnotationParser.java:72)
    at java.lang.Class.createAnnotationData(Class.java:3521)
    at java.lang.Class.annotationData(Class.java:3510)
    at java.lang.Class.getAnnotation(Class.java:3415)
    at org.junit.internal.MethodSorter.getDeclaredMethods(MethodSorter.java:52)
    at org.junit.internal.runners.TestClass.getAnnotatedMethods(TestClass.java:45)
    at org.junit.internal.runners.MethodValidator.validateTestMethods(MethodValidator.java:71)
    at org.junit.internal.runners.MethodValidator.validateStaticMethods(MethodValidator.j

I apologize for such a number of code in my question.

Sergey Luchko
  • 2,996
  • 3
  • 31
  • 51

2 Answers2

1

You probably have conflicting Powermock/Mockito versions. Check your local maven repo for the versions, and get rid of the older ones in your pom and/or update the other dependency which included it.

Check in the root of the project with:

mvn dependency:tree -Dverbose -Dincludes=NAME_OF_DEPENDENCY
Alim Özdemir
  • 2,396
  • 1
  • 24
  • 35
1

You have a conflict of dependent libraries in the TeamCity repo vs your local repo.

Confirm the TC build is using the exact same version of Powermock that your local is using.

There may be an older version being transitively included.

mvn dependency:tree -Dverbose

This will list all the resolvable dependencies. See if there are different versions of Powermock. You can then stop them being possible pulled in by using the exclude/exclusions tag in the pom.xml.

UserF40
  • 3,533
  • 2
  • 23
  • 34