2017-07-21 5 views
0

私のプラグインmojoテストクラスは、maven-plugin-test-harnessを活用して、すべてのpom config、plexusコンテナコンテキストとリポジトリアクセスを持つ完全なmaven環境を構築します。maven-plugin-testing-harnessを使用した厳しい時間のmojoテスト

次は、すべて実際に動作するはずです:

  1. テストはモジョはモジョの注釈すべて
  2. からデフォルト値が取り込まれます
  3. プラグインプロジェクトのテストリソースディレクトリにテストpom.xmlを参照しますテストpomの指定された構成が受け入れられます
  4. mavenプロジェクトオブジェクトが初期化されます
  5. リポジトリからのすべての依存関係が利用可能です
  6. テストがあるので、私はSOから収集したものを使用して、さまざまな修正をしようとし、他のしてきた具体的な作業実施例の不足のCIサーバ

上だけでなく、IntelliJのIDEでMavenを渡す必要がありますブログや記事をオンラインでご覧ください。

現在、mavenにアーチファクトを解決させるのに苦労しています。私はmavenプロジェクトオブジェクトから依存関係リストを取得していますが、アーティファクトリストは空です。

これは私がAbstractMojoTestCaseを解剖して構築したものです。

JUnit5で@Rulesを使用していないため、MojoRuleは使用できません。

さらに、いくつかのmaven API呼び出しは廃止されましたが、新しい実装が見つかりませんでした。私はそれがmvn4まで来ないと思う。以下の見積もりを参照してください。

@BeforeEach 
protected void setUp() throws Exception { 
    super.setUp(); 
    cleanUp(); 
    ClassLoader classLoader = getClass().getClassLoader(); 
    URL url = classLoader.getResource(TEST_POM); 
    if (url == null) { 
     throw new MojoExecutionException(String.format(
       "Cannot locate %s", TEST_POM)); 
    } 
    File pom = new File(url.getFile()); 
    //noinspection deprecation - wait on maven-plugin-testing-harness update 
    MavenSettingsBuilder mavenSettingsBuilder = (MavenSettingsBuilder) 
      getContainer().lookup(MavenSettingsBuilder.ROLE); 
    Settings settings = mavenSettingsBuilder.buildSettings(); 
    MavenExecutionRequest request = new DefaultMavenExecutionRequest(); 
    request.setPom(pom); 
    request.setLocalRepositoryPath(settings.getLocalRepository()); 
    MavenExecutionRequestPopulator populator = 
      getContainer().lookup(MavenExecutionRequestPopulator.class); 
    populator.populateDefaults(request); 
    DefaultMaven maven = (DefaultMaven) getContainer().lookup(Maven.class); 
    DefaultRepositorySystemSession repoSession = 
      (DefaultRepositorySystemSession) 
       maven.newRepositorySession(request); 
    LocalRepository localRepository = new LocalRepository(
      request.getLocalRepository().getBasedir()); 
    SimpleLocalRepositoryManagerFactory factory = 
      new SimpleLocalRepositoryManagerFactory(); 
    LocalRepositoryManager localRepositoryManager = 
      factory.newInstance(repoSession, localRepository); 
    repoSession.setLocalRepositoryManager(localRepositoryManager); 
    ProjectBuildingRequest buildingRequest = 
      request.getProjectBuildingRequest() 
        .setRepositorySession(repoSession) 
        .setResolveDependencies(true); 
    ProjectBuilder projectBuilder = lookup(ProjectBuilder.class); 
    MavenProject project = 
      projectBuilder.build(pom, buildingRequest).getProject(); 
    //noinspection deprecation - wait on maven-plugin-testing-harness update 
    MavenSession session = new MavenSession(getContainer(), repoSession, 
      request, new DefaultMavenExecutionResult()); 
    session.setCurrentProject(project); 
    session.setProjects(Collections.singletonList(project)); 
    request.setSystemProperties(System.getProperties()); 
    testMojo = (GenerateConfig) lookupConfiguredMojo(session, 
      newMojoExecution("configure")); 
    copyTestProjectResourcesToTarget(getContainer(), project, session); 
} 

[UPDATE 2017年7月27日]は:実際には、これが今の私の問題のほとんどを解決します。たぶん私は(MavenSettingsBuilder.buildSettings()を使用して)、それを行うためのより良い方法があるとし

  1. のsettings.xmlをつかむためにコードが@Deprecatedとしてマークされ
  2. :今だけマイナーな問題のいくつ

    かなり多くのセットアップコードは、ネイティブのMavenで動作しているときに発生するプロセスを複製しますが、IntelliJでJUnitを実行する必要があります。

[UPDATE 2017年8月1日]:テストは今target/classesディレクトリでライブ環境でクラスパスになり、いくつかのプロパティファイルにアクセスする必要があります。

論理的には、私のmaven-pluginプロジェクトのテストリソースです。したがって、pom.xmlというディレクトリとsrc/test/resources/my-test-project dirというディレクトリにそれらを含めました。

それはうまくいきませんでしたので、私もsrc/test/resources/my-test-project/src/main/resourcesを試しましたが、それはまた良くありません。

私は、テスト中にプラグインのクラスパスに正確に何が設定されているのか、それが正しく構築されるようにする方法を考え出すのが苦労しています。

[UPDATE 2017-08-02]:私は自分の質問に答えましたが(この質問を延長するのとは対照的に)、この全体がまだ完成していないので、まだ。

そして、ちょうどレコードの、これらは、必要な依存関係です:

<dependency> 
     <groupId>org.junit.jupiter</groupId> 
     <artifactId>junit-jupiter-api</artifactId> 
     <version>5.0.0-M4</version> 
     <scope>test</scope> 
    </dependency> 
    <dependency> 
     <groupId>org.junit.vintage</groupId> 
     <artifactId>junit-vintage-engine</artifactId> 
     <version>4.12.0-M4</version> 
     <scope>test</scope> 
    </dependency> 
    <dependency> 
     <groupId>org.apache.maven</groupId> 
     <artifactId>maven-plugin-api</artifactId> 
     <version>3.5.0</version> 
    </dependency> 
    <dependency> 
     <groupId>org.apache.maven.plugin-tools</groupId> 
     <artifactId>maven-plugin-annotations</artifactId> 
     <version>3.5</version> 
     <scope>provided</scope> 
    </dependency> 
    <dependency> 
     <groupId>org.apache.maven.plugin-testing</groupId> 
     <artifactId>maven-plugin-testing-harness</artifactId> 
     <version>3.3.0</version> 
     <scope>test</scope> 
     <exclusions> 
      <exclusion> 
       <groupId>org.codehaus.plexus</groupId> 
       <artifactId>plexus-container-default</artifactId> 
      </exclusion> 
     </exclusions> 
    </dependency> 
    <dependency> 
     <groupId>org.apache.maven</groupId> 
     <artifactId>maven-core</artifactId> 
     <version>3.5.0</version> 
    </dependency> 
    <dependency> 
     <groupId>org.apache.maven</groupId> 
     <artifactId>maven-compat</artifactId> 
     <version>3.5.0</version> 
     <scope>test</scope> 
    </dependency> 
    <dependency> 
     <groupId>org.twdata.maven</groupId> 
     <artifactId>mojo-executor</artifactId> 
     <version>2.3.0</version> 
     <scope>test</scope> 
    </dependency> 
    <dependency> 
     <groupId>org.apache.maven.plugins</groupId> 
     <artifactId>maven-resources-plugin</artifactId> 
     <version>3.0.2</version> 
     <scope>test</scope> 
    </dependency> 

[UPDATE 2017年8月9日]:

私はいくつかのより多くの機能を追加する必要がありますし、テストすることを発見アンパックしたい依存関係が既にローカルリポジトリにあった場合は問題ありませんでしたが、そうでない場合はフェッチしません。

ここで、リモートリポジトリから依存関係をフェッチするようにmavenに指示する方法を決定する必要があります。

私は依存関係プラグインを起動し、テストセットアップでresolveを呼び出そうとしましたが、ひどく死んでしまいました。私はより簡単な方法が必要だと思います。

+0

まずあなたが意見している場合改善に貢献していない理由、など、文書悪いですそれ ?さらに、これまでに持っていた仕事の完全な実例を見せてもらえますか?私たちがそれを見ることができるギタープロジェクトがベストでしょうか? – khmarbaise

+0

あなたはコミッターですか?私は実際に私のテストを完全に機能させることができることに依存していますが、喜んでサンプルを寄稿/ javadocを改善します。ここで私はmaven-plugin-test-harnessに関するいくつかの質問を見ていますが、プロジェクトを「スムーズ」なアプリにするにはまだ十分ではありません。私もグーグルでは見つけられませんでした。どこかでネット上でディスカッションする必要があると思います。おそらく、検索エンジンによってインデックスが作成されていないmaven用の開発者リストのメールアーカイブですか? – Adam

+0

ユーザーメーリングリストは、http://www.mail-archive.com/[email protected]/で検索できます。あなたのテストがgithubの完全な実例を実行するのを助けることは助けになるでしょう...それを改善するために貢献したいなら、それは素晴らしいことでしょう。 – khmarbaise

答えて

0

リモートリポジトリから依存関係を取得する方法が見つかりました。

このようなmaven内部で作業し、廃止されたクラスと重複した機能の量から判断すると、maven v4によってこれが冗長になるという強い印象を与えてくれます。

この設定ルーチンでは、mavenプロジェクトディレクトリにローカルリポジトリディレクトリツリーが作成されるという欠点があります。これは明らかに望ましいことではありませんが、解決するにはさらに微調整が必​​要です。右のパッケージからのクラスを使用することは非常に重要な

@BeforeEach 
public void setUp() throws Exception { 
    super.setUp(); 
    ClassLoader classLoader = getClass().getClassLoader(); 
    URL url = classLoader.getResource(TEST_POM); 
    if (url == null) { 
     throw new MojoExecutionException(String.format(
       "Cannot locate %s", TEST_POM)); 
    } 
    File pom = new File(url.getFile()); 
    Settings settings = getMavenSettings(); 
    if (settings.getLocalRepository() == null) { 
     settings.setLocalRepository(
       org.apache.maven.repository.RepositorySystem 
         .defaultUserLocalRepository.getAbsolutePath()); 
    } 
    MavenExecutionRequest request = new DefaultMavenExecutionRequest(); 
    request.setPom(pom); 
    ArtifactRepository artifactRepository = 
      new org.apache.maven.artifact.repository. 
        DefaultArtifactRepository(
        "id", settings.getLocalRepository(), 
        new DefaultRepositoryLayout()); 
    request.setLocalRepository(artifactRepository); 
    MavenExecutionRequestPopulator populator = 
      getContainer().lookup(MavenExecutionRequestPopulator.class); 
    populator.populateFromSettings(request, settings); 
    DefaultMaven maven = (DefaultMaven) 
      getContainer().lookup(Maven.class); 
    DefaultRepositorySystemSession repositorySystemSession = 
      (DefaultRepositorySystemSession) 
        maven.newRepositorySession(request); 
    SimpleLocalRepositoryManagerFactory factory = 
      new SimpleLocalRepositoryManagerFactory(); 
    LocalRepositoryManager localRepositoryManager = 
      factory.newInstance(repositorySystemSession, 
        new LocalRepository(settings.getLocalRepository())); 
    repositorySystemSession.setLocalRepositoryManager(
      localRepositoryManager); 
    ProjectBuildingRequest buildingRequest = 
      request.getProjectBuildingRequest() 
        .setRepositorySession(repositorySystemSession) 
        .setResolveDependencies(true); 
    ProjectBuilder projectBuilder = lookup(ProjectBuilder.class); 
    ProjectBuildingResult projectBuildingResult = 
      projectBuilder.build(pom, buildingRequest); 
    MavenProject project = projectBuildingResult.getProject(); 
    MavenSession session = new MavenSession(getContainer(), 
      repositorySystemSession, request, 
      new DefaultMavenExecutionResult()); 
    session.setCurrentProject(project); 
    session.setProjects(Collections.singletonList(project)); 
    request.setSystemProperties(System.getProperties()); 
    testMojo = (GenerateConfig) lookupConfiguredMojo(session, 
      newMojoExecution("configure")); 
    testMojo.getLog().debug(String.format("localRepo = %s", 
      request.getLocalRepository())); 
    copyTestProjectResourcesToTarget(getContainer(), project, session); 
    resolveConfigurationFromRepo(repositorySystemSession, project); 
} 

private Settings getMavenSettings() 
     throws ComponentLookupException, 
      IOException, 
      XmlPullParserException { 
    org.apache.maven.settings.MavenSettingsBuilder mavenSettingsBuilder 
      = (org.apache.maven.settings.MavenSettingsBuilder) 
       getContainer().lookup(
        org.apache.maven.settings.MavenSettingsBuilder.ROLE); 
    return mavenSettingsBuilder.buildSettings(); 
} 

/** 
* This is ugly but there seems to be no other way to accomplish it. The 
* artifact that the mojo finds on its own will not resolve to a jar file 
* on its own in the test harness. So we use aether to resolve it, by 
* cloning the maven default artifact into an aether artifact and feeding 
* an artifact request to the repo system obtained by the aether service 
* locator. 
*/ 
private void resolveConfigurationFromRepo(
     DefaultRepositorySystemSession repositorySystemSession, 
     MavenProject project) 
     throws ArtifactResolutionException, MojoExecutionException { 
    org.apache.maven.artifact.Artifact defaultArtifact = 
      testMojo.getConfigArtifact(); 
    Artifact artifact = new DefaultArtifact(
      defaultArtifact.getGroupId(), 
      defaultArtifact.getArtifactId(), 
      null, 
      defaultArtifact.getType(), 
      defaultArtifact.getVersion()); 
    List<RemoteRepository> remoteArtifactRepositories = 
      project.getRemoteProjectRepositories(); 
    DefaultServiceLocator locator = 
      MavenRepositorySystemUtils.newServiceLocator(); 
    locator.addService(RepositoryConnectorFactory.class, 
      BasicRepositoryConnectorFactory.class); 
    locator.addService(TransporterFactory.class, 
      FileTransporterFactory.class); 
    locator.addService(TransporterFactory.class, 
      HttpTransporterFactory.class); 
    RepositorySystem repositorySystem = locator.getService(
      RepositorySystem.class); 
    ArtifactRequest artifactRequest = new ArtifactRequest(); 
    artifactRequest.setArtifact(artifact); 
    artifactRequest.setRepositories(remoteArtifactRepositories); 
    ArtifactResult result = repositorySystem.resolveArtifact(
      repositorySystemSession, artifactRequest); 
    defaultArtifact.setFile(result.getArtifact().getFile()); 
    testMojo.getLog().debug("Resolved artifact " + artifact + " to " + 
      result.getArtifact().getFile() + " from " 
      + result.getRepository()); 
} 


/** 
* Need manual copy of resources because only parts of the maven lifecycle 
* happen automatically with this test harness. 
*/ 
private void copyTestProjectResourcesToTarget(PlexusContainer container, 
               MavenProject project, 
               MavenSession session) 
     throws ComponentLookupException, MojoExecutionException { 
    Optional<Dependency> resourcesPluginDepOpt = 
      project.getDependencies().stream() 
        .filter(d -> Objects.equals(d.getArtifactId(), 
          MAVEN_RESOURCES_ARTIFACT_ID)) 
        .findFirst(); 
    // don't want to define the version here so we read it from what we have 
    if (!resourcesPluginDepOpt.isPresent()) { 
     throw new MojoExecutionException("Require " + 
       MAVEN_RESOURCES_ARTIFACT_ID); 
    } 
    Plugin resourcePlugin = MojoExecutor.plugin(
      MojoExecutor.groupId(MAVEN_PLUGINS_GROUP_ID), 
      MojoExecutor.artifactId(MAVEN_RESOURCES_ARTIFACT_ID), 
      MojoExecutor.version(resourcesPluginDepOpt.get().getVersion())); 
    MojoExecutor.executeMojo(resourcePlugin, 
      MojoExecutor.goal("resources"), 
      MojoExecutor.configuration(), 
      MojoExecutor.executionEnvironment(
        project, session, 
        container.lookup(BuildPluginManager.class))); 
} 

、ここでは使用されたパッケージですが、簡単に混乱:

import org.apache.maven.DefaultMaven; 
import org.apache.maven.Maven; 
import org.apache.maven.artifact.repository.ArtifactRepository; 
import org.apache.maven.artifact.repository.layout.DefaultRepositoryLayout; 
import org.apache.maven.execution.DefaultMavenExecutionRequest; 
import org.apache.maven.execution.DefaultMavenExecutionResult; 
import org.apache.maven.execution.MavenExecutionRequest; 
import org.apache.maven.execution.MavenExecutionRequestPopulator; 
import org.apache.maven.execution.MavenSession; 
import org.apache.maven.model.Dependency; 
import org.apache.maven.model.Plugin; 
import org.apache.maven.plugin.BuildPluginManager; 
import org.apache.maven.plugin.MojoExecutionException; 
import org.apache.maven.plugin.MojoFailureException; 
import org.apache.maven.plugin.testing.AbstractMojoTestCase; 
import org.apache.maven.project.MavenProject; 
import org.apache.maven.project.ProjectBuilder; 
import org.apache.maven.project.ProjectBuildingRequest; 
import org.apache.maven.project.ProjectBuildingResult; 
import org.apache.maven.repository.internal.MavenRepositorySystemUtils; 
import org.apache.maven.settings.Settings; 
import org.codehaus.plexus.PlexusContainer; 
import org.codehaus.plexus.component.repository.exception.ComponentLookupException; 
import org.codehaus.plexus.util.xml.pull.XmlPullParserException; 
import org.eclipse.aether.DefaultRepositorySystemSession; 
import org.eclipse.aether.RepositorySystem; 
import org.eclipse.aether.artifact.Artifact; 
import org.eclipse.aether.artifact.DefaultArtifact; 
import org.eclipse.aether.connector.basic.BasicRepositoryConnectorFactory; 
import org.eclipse.aether.impl.DefaultServiceLocator; 
import org.eclipse.aether.internal.impl.SimpleLocalRepositoryManagerFactory; 
import org.eclipse.aether.repository.LocalRepository; 
import org.eclipse.aether.repository.LocalRepositoryManager; 
import org.eclipse.aether.repository.RemoteRepository; 
import org.eclipse.aether.resolution.ArtifactRequest; 
import org.eclipse.aether.resolution.ArtifactResolutionException; 
import org.eclipse.aether.resolution.ArtifactResult; 
import org.eclipse.aether.spi.connector.RepositoryConnectorFactory; 
import org.eclipse.aether.spi.connector.transport.TransporterFactory; 
import org.eclipse.aether.transport.file.FileTransporterFactory; 
import org.eclipse.aether.transport.http.HttpTransporterFactory; 
0

MavenProjectためのMavenのソースコードの一部のコメントが3.2.2リリースMavenProject時の変更により

は、このクラスのすべてのコンポーネントの除去と建設後に不変であることに近く、先行建設が取られました@ {ProjectBuilder}によって完全に管理されています。すべてのコンパイル元のルートとリソースディレクトリを見つけるためにライフサイクルを実行する必要があるという問題は残っていますが、Maven 4.0リリース(jvz)でこれを処理したいと考えています。私は、この全体のMavenプラグインの統合テストの事は、私はa great blog entry on invoking pluginsを見つけ、それまで仕事に行く...ので周りを探していません。理解

そこで私はmaven-resources-pluginを直接呼び出して、それが意味するものをコピーするようにしました。それがcopyTestProjectResourcesToTarget()の呼び出しです。

private void copyTestProjectResourcesToTarget(PlexusContainer container, 
               MavenProject project, 
               MavenSession session) 
     throws ComponentLookupException, MojoExecutionException { 
    logger.fine("generateConfig dependencies: "); 
    project.getDependencies().forEach(d -> logger.fine(d.getArtifactId())); 
    Optional<Dependency> resourcesPluginDepOpt = 
      project.getDependencies().stream() 
        .filter(d -> Objects.equals(d.getArtifactId(), 
          MAVEN_RESOURCES_ARTIFACT_ID)) 
        .findFirst(); 
    // don't want to define the version here so we read it from what we have 
    if (!resourcesPluginDepOpt.isPresent()) { 
     throw new MojoExecutionException("Require " + 
       MAVEN_RESOURCES_ARTIFACT_ID); 
    } 
    Plugin resourcePlugin = MojoExecutor.plugin(
      MojoExecutor.groupId(MAVEN_RESOURCES_GROUP_ID), 
      MojoExecutor.artifactId(MAVEN_RESOURCES_ARTIFACT_ID), 
      MojoExecutor.version(resourcesPluginDepOpt.get().getVersion())); 
    MojoExecutor.executeMojo(resourcePlugin, 
      MojoExecutor.goal("resources"), 
      MojoExecutor.configuration(), 
      MojoExecutor.executionEnvironment(
        project, session, 
        container.lookup(BuildPluginManager.class))); 
} 
関連する問題