1

The maven plugin I am developing now injects some dependencies using Google Guice with JSR-330. For unit testing I am using maven-plugin-testing-harness. The plugin works perfectly. But there is a problem with tests. I want to inject mocked components into mojo, but still there are real objects in tests.

I've tried to write my custom test module as it's said in Google Guice Bound Field, but it didn't work. After some debugging I found out that Plexus container doesn't allow to use custom modules.

There are my mojo:

package my.maven.plugins.myplugin;

import my.maven.plugins.myplugin.component.MyComponent;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.project.MavenProject;

import javax.inject.Inject;

@Mojo(name = "resolve-property-value")
public class MyMojo extends AbstractMojo {

    private final MyComponent component;

    @Parameter(readonly = true, defaultValue = "${project}" )
    private MavenProject project;

    @Inject
    public MyMojo(MyComponent component) {
        this.component = component;
    }

    @Override
    public void execute() {
        String value = component.resolvePropertyValue();
        project.getProperties().setProperty("some.property", value);
    }
}

Component's interface:

package my.maven.plugins.myplugin.component;

public interface MyComponent {

    String resolvePropertyValue();
}

And implementation

package my.maven.plugins.myplugin.component.impl;

import my.maven.plugins.myplugin.component.MyComponent;

import javax.inject.Named;

@Named
public class MyComponentImpl implements MyComponent {

    @Override
    public String resolvePropertyValue() {
        return "someValue";
    }
}

Test:

package my.maven.plugins.myplugin;

import my.maven.plugins.myplugin.component.MyComponent;
import org.apache.maven.plugin.Mojo;
import org.apache.maven.plugin.testing.MojoRule;
import org.apache.maven.project.MavenProject;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;

import java.util.Properties;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.doReturn;

public class MyMojoTest {

    @Mock
    private MyComponent component;

    @Rule
    public MojoRule mojoRule = new MojoRule();

    @Before
    public void setUp() {
        MockitoAnnotations.initMocks(this);
    }

    @Test
    public void should_set_some_property() throws Exception {
        doReturn("testValue").when(component).resolvePropertyValue();
        MavenProject project = new MavenProject();
        Mojo goal = mojoRule.lookupConfiguredMojo(project, "resolve-property-value");
        goal.execute();
        Properties properties = project.getProperties();
        assertTrue(properties.containsKey("some.property"));
        assertEquals("testValue", properties.get("some.property"));
    }
}

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>my.maven.plugins</groupId>
    <artifactId>my-plugin</artifactId>
    <version>0.1.0-SNAPSHOT</version>
    <packaging>maven-plugin</packaging>

    <properties>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>

        <maven.version>3.6.0</maven.version>
        <maven-test.version>3.3.0</maven-test.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.apache.maven</groupId>
            <artifactId>maven-core</artifactId>
            <version>${maven.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.maven</groupId>
            <artifactId>maven-plugin-api</artifactId>
            <version>${maven.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.maven.plugin-tools</groupId>
            <artifactId>maven-plugin-annotations</artifactId>
            <version>${maven.version}</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>com.google.guava</groupId>
            <artifactId>guava</artifactId>
            <version>21.0</version>
        </dependency>
        <dependency>
            <groupId>org.apache.maven.resolver</groupId>
            <artifactId>maven-resolver-api</artifactId>
            <version>1.3.1</version>
        </dependency>
        <dependency>
            <groupId>org.apache.maven</groupId>
            <artifactId>maven-compat</artifactId>
            <version>${maven.version}</version>
            <scope>test</scope>
        </dependency>

        <!-- Test dependencies -->
        <dependency>
            <groupId>org.apache.maven.plugin-testing</groupId>
            <artifactId>maven-plugin-testing-harness</artifactId>
            <version>${maven-test.version}</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.mockito</groupId>
            <artifactId>mockito-core</artifactId>
            <version>2.23.4</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <pluginManagement>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-plugin-plugin</artifactId>
                    <version>${maven.version}</version>
                </plugin>
            </plugins>
        </pluginManagement>
    </build>
</project>

Is there any way to use mockito in plugin unit tests?

  • I don't see any code that would supply the `component` mock to the `MyMojo` class. How is the object construction with the `mojoRule` supposed to do that on its own? – second Mar 17 '20 at 09:41
  • That is my question. I can't find any guide or example how to do it. I've tried to create a custom guice module with mock binding, but it didn't work. I am not sure whether it's possible to use mockito here at all. But I suppose as it is a unit test there should be a solution to replace the real component – Gibadullina Elvira Mar 17 '20 at 11:18
  • @second, thank you. I've tried to find some implicit ways to inject a mock. But after your comment I've made another research of Plexus container's methods and found the one in my answer. I'm not pleased with the solution, but will stay with it. – Gibadullina Elvira Mar 17 '20 at 11:39

1 Answers1

2

I suppose there is no "magic" ways to inject mocked components. So I've decided to put it into container explicitly in setUp section

@Before
public void setUp() {
    MockitoAnnotations.initMocks(this);
    mojoRule.getContainer().addComponent(component, MyComponent.class, "");
}
  • Unless you have control over the object creation, you can't really use the "magic" `mockito` provides by default. As a fallback `reflections` are always an option, however this approach looks better. – second Mar 17 '20 at 16:02