raiki_dev’s blog

右も左も分かりませんが、よろしくお願いいたします。

【JUnit5】TestEngine with ID 'junit-platform-suite' failed to discover tests

 

 

1. 結論

端的に言うとintellijで実行できていたテストコードを既に存在するEclipseプロジェクトに移植し、テストコードを実行すると発生したエラー。

結論、既存プロジェクトがEclipse内のJUnitライブラリを使用しており、自分で入れたJUnitのバージョンとあっておらず、依存関係が合わずエラーが出ていた模様。 Eclipse内のライブラリを依存関係から外すことで解決した。(画像1)

大規模プロジェクトで、プロジェクト同士が依存関係になっており、テストコードを使ってるプロジェクトが参照しているプロジェクトでEclipse内のJunitを参照していたので、気づかずに発見が遅れた。

2024 03 10T12 30 52 309Z

画像1:Eclipse内のJunitライブラリ

2. 経緯

  1. 上述した通り、eclipseにテストコードやライブラリ含めて移動させたら、エラーが出た。エラー1

  2. 調べてみると、この類のエラーはどうやら、Junitの依存関係がおかしそうだ。参考情報

  3. 今まで使っていたJunitライブラリの組み合わせは安定に動いてたこともあり、おかしそうな点も見当たらない。

  4. 何がおかしいのかJunitについて深く調べていく

    1. JUnitは、engineを依存関係に登録すると、platformと、apiが内包されていることがわかった

    2. 依存関係をすべて解決してくれるAllInOne的な銀の弾丸的なリポジトリを発見する

      1. https://repo1.maven.org/maven2/org/junit/platform/junit-platform-console-standalone/

        1. このall in oneをもってしても、違うエラーが出る

  5. さすがにおかしいと、Eclipseのほうの依存関係に焦点を絞り疑っていく

    1. Eclipseに同梱されてるJunitがあることを発見(6)

    2. 依存関係を洗いまくったら、JUnit5がいることを発見した

  6. 除去してテストコードを実行すると、エラー無く完了

3. 参考情報

3.1. エラー1

3 09, 2024 2:06:52 午後 org.junit.platform.launcher.core.DefaultLauncher handleThrowable
警告: TestEngine with ID 'junit-platform-suite' failed to discover tests
java.lang.NoSuchMethodError: org.junit.platform.engine.EngineDiscoveryRequest.getDiscoveryListener()Lorg/junit/platform/engine/EngineDiscoveryListener;
	at org.junit.platform.engine.support.discovery.EngineDiscoveryRequestResolution.resolveCompletely(EngineDiscoveryRequestResolution.java:89)
	at org.junit.platform.engine.support.discovery.EngineDiscoveryRequestResolution.run(EngineDiscoveryRequestResolution.java:83)
	at org.junit.platform.engine.support.discovery.EngineDiscoveryRequestResolver.resolve(EngineDiscoveryRequestResolver.java:113)
	at org.junit.platform.suite.engine.DiscoverySelectorResolver.resolveSelectors(DiscoverySelectorResolver.java:41)
	at org.junit.platform.suite.engine.SuiteTestEngine.discover(SuiteTestEngine.java:58)
	at org.junit.platform.launcher.core.DefaultLauncher.discoverEngineRoot(DefaultLauncher.java:130)
	at org.junit.platform.launcher.core.DefaultLauncher.discoverRoot(DefaultLauncher.java:117)
	at org.junit.platform.launcher.core.DefaultLauncher.discover(DefaultLauncher.java:82)
	at org.eclipse.jdt.internal.junit5.runner.JUnit5TestReference.<init>(JUnit5TestReference.java:42)
	at org.eclipse.jdt.internal.junit5.runner.JUnit5TestLoader.createUnfilteredTest(JUnit5TestLoader.java:73)
	at org.eclipse.jdt.internal.junit5.runner.JUnit5TestLoader.createTest(JUnit5TestLoader.java:63)
	at org.eclipse.jdt.internal.junit5.runner.JUnit5TestLoader.loadTests(JUnit5TestLoader.java:50)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:522)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:760)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:460)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:206)

3 09, 2024 2:06:52 午後 org.junit.platform.launcher.core.DefaultLauncher handleThrowable
警告: TestEngine with ID 'junit-platform-suite' failed to discover tests
java.lang.NoSuchMethodError: org.junit.platform.engine.EngineDiscoveryRequest.getDiscoveryListener()Lorg/junit/platform/engine/EngineDiscoveryListener;
	at org.junit.platform.engine.support.discovery.EngineDiscoveryRequestResolution.resolveCompletely(EngineDiscoveryRequestResolution.java:89)
	at org.junit.platform.engine.support.discovery.EngineDiscoveryRequestResolution.run(EngineDiscoveryRequestResolution.java:83)
	at org.junit.platform.engine.support.discovery.EngineDiscoveryRequestResolver.resolve(EngineDiscoveryRequestResolver.java:113)
	at org.junit.platform.suite.engine.DiscoverySelectorResolver.resolveSelectors(DiscoverySelectorResolver.java:41)
	at org.junit.platform.suite.engine.SuiteTestEngine.discover(SuiteTestEngine.java:58)
	at org.junit.platform.launcher.core.DefaultLauncher.discoverEngineRoot(DefaultLauncher.java:130)
	at org.junit.platform.launcher.core.DefaultLauncher.discoverRoot(DefaultLauncher.java:117)
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:90)
	at org.eclipse.jdt.internal.junit5.runner.JUnit5TestReference.run(JUnit5TestReference.java:86)
	at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:538)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:760)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:460)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:206)

java.lang.NoSuchMethodError: org.junit.platform.launcher.TestPlan.getConfigurationParameters()Lorg/junit/platform/engine/ConfigurationParameters;
	at org.junit.platform.launcher.listeners.UniqueIdTrackingListener.testPlanExecutionStarted(UniqueIdTrackingListener.java:140)
	at org.junit.platform.launcher.core.TestExecutionListenerRegistry$CompositeTestExecutionListener.lambda$testPlanExecutionStarted$4(TestExecutionListenerRegistry.java:82)
	at java.util.ArrayList.forEach(ArrayList.java:1257)
	at org.junit.platform.launcher.core.TestExecutionListenerRegistry.notifyTestExecutionListeners(TestExecutionListenerRegistry.java:51)
	at org.junit.platform.launcher.core.TestExecutionListenerRegistry.access$100(TestExecutionListenerRegistry.java:27)
	at org.junit.platform.launcher.core.TestExecutionListenerRegistry$CompositeTestExecutionListener.testPlanExecutionStarted(TestExecutionListenerRegistry.java:82)
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:149)
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:90)
	at org.eclipse.jdt.internal.junit5.runner.JUnit5TestReference.run(JUnit5TestReference.java:86)
	at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:538)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:760)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:460)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:206)

3.2. エラー2

java.lang.NoSuchMethodError: org.junit.jupiter.api.extension.ExtensionContext.getTestInstances()Ljava/util/Optional;
	at base..BaseExtension.getTestClassInstance(BaseExtension.java:41)
	at base..BaseExtension.beforeTestExecution(BaseExtension.java:177)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$null$4(TestMethodTestDescriptor.java:138)
	at org.junit.jupiter.engine.execution.ThrowableCollector.execute(ThrowableCollector.java:40)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeBeforeMethodsOrCallbacksUntilExceptionOccurs(TestMethodTestDescriptor.java:152)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeBeforeTestExecutionCallbacks(TestMethodTestDescriptor.java:137)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:108)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:57)
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.lambda$execute$3(HierarchicalTestExecutor.java:83)
	at org.junit.platform.engine.support.hierarchical.SingleTestExecutor.executeSafely(SingleTestExecutor.java:66)
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:77)
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.lambda$null$2(HierarchicalTestExecutor.java:92)
	at java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:184)
	at java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:175)
	at java.util.Iterator.forEachRemaining(Iterator.java:116)
	at java.util.Spliterators$IteratorSpliterator.forEachRemaining(Spliterators.java:1801)
	at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:481)
	at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471)
	at java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:151)
	at java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:174)
	at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
	at java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:418)
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.lambda$execute$3(HierarchicalTestExecutor.java:92)
	at org.junit.platform.engine.support.hierarchical.SingleTestExecutor.executeSafely(SingleTestExecutor.java:66)
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:77)
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.lambda$null$2(HierarchicalTestExecutor.java:92)
	at java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:184)
	at java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:175)
	at java.util.Iterator.forEachRemaining(Iterator.java:116)
	at java.util.Spliterators$IteratorSpliterator.forEachRemaining(Spliterators.java:1801)
	at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:481)
	at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471)
	at java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:151)
	at java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:174)
	at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
	at java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:418)
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.lambda$execute$3(HierarchicalTestExecutor.java:92)
	at org.junit.platform.engine.support.hierarchical.SingleTestExecutor.executeSafely(SingleTestExecutor.java:66)
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:77)
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:51)
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:43)
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:170)
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:154)
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:90)
	at org.eclipse.jdt.internal.junit5.runner.JUnit5TestReference.run(JUnit5TestReference.java:86)
	at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:538)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:760)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:460)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:206)
	Suppressed: java.lang.NoSuchMethodError: org.junit.jupiter.api.extension.ExtensionContext.getTestInstances()Ljava/util/Optional;
		at base..BaseExtension.getTestClassInstance(BaseExtension.java:41)
		at base..BaseExtension.afterTestExecution(BaseExtension.java:201)
		at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$null$7(TestMethodTestDescriptor.java:201)
		at org.junit.jupiter.engine.execution.ThrowableCollector.execute(ThrowableCollector.java:40)
		at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeAllAfterMethodsOrCallbacks$13(TestMethodTestDescriptor.java:226)
		at java.util.ArrayList.forEach(ArrayList.java:1257)
		at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeAllAfterMethodsOrCallbacks(TestMethodTestDescriptor.java:224)
		at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeAfterTestExecutionCallbacks(TestMethodTestDescriptor.java:200)
		at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:112)
		... 43 more

3.3. _安定に動いてたはずのMaven依存関係

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <junit.jupiter.version>5.9.1</junit.jupiter.version>
        <junit.platform.version>1.9.1</junit.platform.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-engine</artifactId>
            <version>${junit.jupiter.version}</version>
        </dependency>
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-api</artifactId>
            <version>${junit.jupiter.version}</version>
        </dependency>
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-params</artifactId>
            <version>${junit.jupiter.version}</version>
        </dependency>
        <dependency>
            <groupId>org.junit.platform</groupId>
            <artifactId>junit-platform-suite</artifactId>
            <version>${junit.platform.version}</version>
        </dependency>

3.4. 参考文献

  1. [spring boot - JUnit java.lang.NoSuchMethodError: org.junit.jupiter.api.extension.ExtensionContext.getRequiredTestInstances() - Stack Overflow](https://stackoverflow.com/questions/60471228/junit-java-lang-nosuchmethoderror-org-junit-jupiter-api-extension-extensioncont)

  2. [JUnit 5 ユーザーガイド](https://junit.org/junit5/docs/current/user-guide/#running-tests-ide-eclipse)

  3. [spring boot - JUnit java.lang.NoSuchMethodError: org.junit.jupiter.api.extension.ExtensionContext.getRequiredTestInstances() - Stack Overflow](https://stackoverflow.com/questions/60471228/junit-java-lang-nosuchmethoderror-org-junit-jupiter-api-extension-extensioncont)

  4. [Maven Surefireプラグイン - JUnit 5プラットフォームの使用 (apache.org)](https://maven.apache.org/surefire/maven-surefire-plugin/examples/junit-platform.html)

  5. [【SpringBoot】SpringBoot2.0.9 → 2.1.9でテストを実行できなくなった状況への対処【JUnit5】 #SpringBoot - Qiita](https://qiita.com/wrongwrong/items/9e2f89272329af73adba)

  6. [JUnitEclipseに同梱されるようになっていた件 - ts0818のブログ (hatenablog.com)](https://ts0818.hatenablog.com/entry/2023/03/12/113320)

VSCodeのプラグイン簡単に作れた【base64-image-embedder】

VSCodeプラグイン作ってみた所感。

はじめての TypeScript で、はじめての VSCode プラグイン 開発であったが、機能が簡単なこともあり、作り方をググり始めてから公開するまで込々で6時間ぐらいで作れた。

公式や日本語記事の参考情報も豊富で、時代に感謝。参考サイトを載せておくので、それを見れば皆作れるはず。(1)(2)(3)

手軽に作ったプラグインVsCodeの検索で普通に出てきたときは感動した。

成果物

marketplace.visualstudio.com

※現状、htmlファイル内のローカルイメージパスをすべて、base64に変換するだけの機能

今回作ったプラグインで解決したいこと

他の記事でも何回か言及してるが、はてなブログの記事に投稿するために、手元にある(ローカルに保存されている)markdownやasciidocなどの資源をhtmlに変換して、はてなブログのhtmlを貼り付けてそのまま投稿する機能を使って記事を投稿する際、ローカルに依存する画像パスがhtmlに含まれていたら、当然はてなにhtmlだけコピペしても画像が表示できないので、html内のイメージパスの画像を読み取ってbase64に変換し、htmlに上書きすることで、そのままはてなブログの記事にできるのではないかという動機。

参考情報

ネットの皆さまいつも助かってます。ありがとう。

  1. VSCode Extensions(拡張機能) 自作入門 〜VSCodeにおみくじ機能を追加する〜 #VSCode - Qiita
  2. PowerShellでこのシステムではスクリプトの実行が無効になっているため、ファイル hoge.ps1 を読み込むことができません。となったときの対応方法 #Windows10 - Qiita
  3. Publishing Extensions | Visual Studio Code Extension API

GistでSecret解除方法

 

 

Gist でとある自分の公開したと認識していたソースが Secret となっていることに気づいた。 少し調べると Secret 状態は、URLを知っている人なら自分以外でも見れる状態であるらしい。

これを Public にして他人が検索もできるようにするには、Webページから編集ボタン Edit をクリックして、 Make public をクリックするとよい。

※一度 Public にしたものは Secret に戻すことはできないので注意が必要 公式より

vscode-plantumlのフォーマッタでbreakを使うと崩れる

breakが崩れる

breakを使うとインデントが崩れた。。 下記は公式のissueでまだcloseされていない。 そもそも公式の見解としては致命的な問題があるので、vscodeの設定で保存時自動フォーマットの設定をONにしていると、フォーマットが機能しないようになっている。 それでもフォーマット使いたかったので、一旦自動保存フォーマットの設定をOFFにしてみたが、案の定問題に遭遇したという経緯

The 'break' keyword causes problems when formatting · Issue #477 · qjebbs/vscode-plantuml · GitHub

issueによると、以下のようで解決が難しそう。 breakの代案としてlabelを使ってみたが、うまくいかない場合が多いので断念。

アクティビティ図のbreakが崩れる例についてはチケットを参考に。

Before formatting:

@startuml
start
repeat
    if (Abort?) then (yes)
      :Cleanup;
      break
    endif
    :Do Something;
repeat while (Completed?) is (no)
stop
@enduml

After formatting:

@startuml
start
repeat
  if (Abort?) then (yes)
    :Cleanup;
    break
    endif
    :Do Something;
  repeat while (Completed?) is (no)
  stop
  @enduml

ソースコードの「FormatRules.ts」を少し確認しました。 この問題は、PlantUMLの「break」キーワードがシーケンス図ではブロックキーワードであるが、アクティビティ図ではブロックキーワードではないことが原因です。 しかし、キーワードベースのフォーマッタでは、同じキーワードを異なるコンテキストとして考慮する必要があるため、この問題を解決するのは簡単ではないようです。

while(名前)が崩れる

before

while(フラグがtrueになるまで)
        :処理;
endwhile

after

while
        (フラグがtrueになるまで)
        :処理;
endwhile

別の記事でも崩れる事例あり

別の日本の記事でもフォーマットが崩れる事案があった。

VS CodeでPlantUMLのフォーマットを行うとインデントが崩れる場合の回避方法

結論

おとなしくフォーマッタを切るしかないのかな。。。。。。。。。。

Asciidocいいぞという話

Asciidocに出会うまでの歴史

煩悩まみれでノート管理難民に

きっかけを遡ると新卒として部署に配属されたてのことから、いろいろ思考整理のメモなどをまとめるアプリを探してNotionに落ち着いたが、他人に文書を共有するときWeb表示可能ではあるが結局Notionというプラットフォームに依存することが気になっていた。 Notionに詳しい人はMarkdownとしてExportすることでいざという時に自分の文書として手元に永久保存できるのではないかと思うだろう。 しかし少し凝ったレイアウトや貼り付けファイル内容次第では使い物にならなかったり、HTML出力したときに今はどうか知らないがページのプロパティなどがデフォルトで表示されてということ満足するレベルではなかった。

つまるところ今後何があるか分からないので、自分用のメモであったり思考整理内容、欲を言えば報告資料や技術文書など資料にまとめるという行為に対して、ある程度ストレスなく万人が読めて、メモする行為自体もストレスにならない形を求めていた。 かつそれを汎用的な形で永久に保存し辞書のように参照できたらいいなとも考えていたのだ。 また、他人に共有するときにオフラインの資料として綺麗な見た目で提出できることも望ましい。

今自分で振り返ってみて、改めて強欲すぎないかと可笑しくなってくる。

Markdownでの実現可能性

ざっくりとそのような煩悩まみれの条件下のもとMarkdownの可能性を探り始めた。 Markdownという形が無くならない限りある程度汎用的に永久保存できそうではあったし、HTMLに変換することでMarkdownを知らない人や描画できる環境に無い人にも共有できるし、オフラインでも見てもらえるので良いかと考えた。 ただ、メモ的なものであればそれで十分ではあったが、真面目な文章量が多めの技術文書や調査資料を作成する際に、文書の全体像が分かりにくいという問題に直面した。

そこで文書の全体像が把握できるものを色々自身の経験より思い返してみると、Androidの個人開発をしていたときにお世話になっていたAndroiDeveloperという公式Webドキュメントを思い出した。 ページの左側がアウトラインになっており、全体を把握でき、クリックすると該当ページにジャンプしたり遷移したりすることができるのだ。

参考:https://developer.android.com/

求めるものが定まったところで、MarkDownがその要件を満たしてくれるのか調査した。 当然のことながら、独自MarkDownエディタや、プラグイン上での描画でOutlineが表示されているだけではNGであり、HTMLで表示したときにアウトラインを構築できるかどうかがポイントとなる。

色々調べた結果アウトライン表示できるものとして、以下候補が挙がった。

まずDocFx, docusaurus, honkitは基本的にローカルサーバを立ててブラウザからlocalhostに対してhtmlをブラウジングする形となる。 それでは、他人に文書を共有するときにあまりにも汎用性が低く表示してもらうためのストレスが大きいので当然却下。 ただ、honkitだけはexportしたhtmlファイルが./_bookというパスにあり、index.htmlを直接ブラウザで表示しても描画でき、UIとか操作感など文句が無いものであったように見えたため期待させられたが、ページ遷移などにfile:///パスを使ってるせいでCORSエラーが発生しており、ページ遷移など全く機能しなかったので使えなかった。

markdown-preview-enhancedはvscodeプラグインであり、exportする形式としてhtmlを選択でき、exportされたhtmlはoutlineが表示されており、各セクションへのジャンプも可能であった。 これだと思い、しばらく使ってみた。 要件は満たしていたので、細かい部分には目を瞑りしばらく使っていて当然ある程度運用は出来た。 しかし私は上位互換に出会ってしまったのだ。 それがAsciidocであった。

Asciidocのことを書く前に、markdown-preview-enhancedでoutlineを表示するための私用のヘッダー記述を公開しているのでリンクを貼っておく。

Asciidocとの出会い

あるOSSgithubソースをみたときに、readmeがmdではなくadocとなっていた。 これは何だと思い調べたのが出会い。

Asciidocの細かい利点については割愛するが、上述した懸念点を解消してくれた他に実際に触ってみて感じた私的大きなメリットは以下である。

  1. Markdown記法でも書ける
  2. include::ファイル名 で別のファイルの内容をその場に展開できる。
  3. 階層化したリストや見出しに番号を自動で振ることができる
  4. outlineもデフォルトで対応している
  5. github, gitlabが標準で描画対応している。

4についてはAsciidoctorというプラグイン依存の内容ではあるが、現状このプラグインが一強のようだ。 機能だけでいうとMarkdownの純粋な上位互換なんじゃないかと思う。

サンプルイメージは以下のような感じ。

プラグインだけで完結する簡単な環境

  1. vscode上に以下のプラグインを入れる

t.co

  1. コードブロックの表示にhighlight.jsを選択する(ほかの表示方法はRubyのインストールが必要) Highlight.js | Asciidoctor Docs

  2. pasteimageプラグインをいれて画像をコピペで貼り付けれるようにする Paste Image - Visual Studio Marketplace

私のテンプレートも載せておく

心残り

一度HatenaBlogにもAsciidocからエクスポートした記事を試しに載せた( 意識高い系にならないように - raiki_dev’s blog )が、画像や外部ファイルがローカルパス依存のためhtmlの中身だけをコピーだと当然だが、画像など見当たらない。 なのでブログなどに載せるとなると外部ファイル取り込みに関して制約が発生する。 この記事も迷ったが、画像を入れたかったのでブログに直接書いた。

また、縦型のDisplayで自分のブログを表示したときに、本文にアウトラインが食い込んでいたので、アウトラインを外す設定をした。この辺りは試行錯誤が必要かもしれない。

最低限画像をhtml内に組み込めるとなると幅が広がりそうだ。 一度htmlにエクスポートした文書に対して、html内の画像パスがローカルであれば、バイナリに変換するツールなどを時間があれば作ろうと思う。

JUnit5で引数の名前と値を取得する方法

JUnit5でテストメソッドの引数の変数名と値を取得したい場合があり、公式GithubのIssueのコメントで流れているとこを発見したので記載しておく。

下記は@BeforeEachを実施する際にフックするメソッド内で該当情報を取得している例だ。 サンプルとして変数名と、変数の値をSysoutするようにしたので編集すれば好きなように使うことができる。 なお、普通に実行しても引数名はargNとなるが、-parametersとJVMOptionを追記することで引数名が取れるようになる。

私の場合、引数名と値と、別途テストクラスの階層やテストクラスを取得することで、実行したときのエビデンス出力するフォルダ構成を作成するために利用した。

class TestExtension
        implements BeforeEachCallback
{
    @Override
    public void beforeEach(ExtensionContext extensionContext)
    {
        Parameter[] parameters = extensionContext.getTestMethod().get().getParameters();
        Object[] argObjects = getArgumentValues(extensionContext);
        for (int i = 0; i < parameters.length; i++)
        {
            // ここで引数名と値を出力している
            System.out.println(parameters[i].getName() + " : " + argObjects[i]);
        }
    }

    private Object[] getArgumentValues(ExtensionContext extensionContext)
    {
        try
        {
            Method method = ReflectionUtils.findMethod(extensionContext.getClass(), "getTestDescriptor").orElse(null);
            TestMethodTestDescriptor descriptor =
                    (TestMethodTestDescriptor)ReflectionUtils.invokeMethod(method, extensionContext);

            //Get the TestTemplateInvocationContext
            Field templateField = descriptor.getClass().getDeclaredField("invocationContext");
            templateField.setAccessible(true);
            TestTemplateInvocationContext template = (TestTemplateInvocationContext)templateField.get(descriptor);

            //Get the params finally
            Field argumentsField = template.getClass().getDeclaredField("arguments");
            argumentsField.setAccessible(true);
            Object[] params = (Object[])argumentsField.get(template);

            return params;

        }
        catch (Exception e)
        {
            return new Object[0];
        }
    }
}

参考

この記事は過去にZennに投稿したものの転載。 zenn.dev

意識高い系にならないように

 

 

特に新人の頃はそうだが、仕事ができない人間というレッテルを貼られないために、意識的または無意識に仕事ができる人として振る舞うために背伸びをしている人は私の観測範囲では多い。 それを続けることによって、背伸びした自分と少しずつ同化していく人は一定数居るとは思う。 一方で疲れて演じるのを止める人もいれば仕事自体に疲れて病んでしまう人も居る。

私は新人の頃、保身のために仕事が出来る人間になろうと意識していたと思う。 しかし疲れてしまい意識するのを止めたと自己分析している。 その心境に至った理由と、止めてみて良かったと思っている。

持論をここに書いてみる。

※偏見だらけなので注意

1. なぜ人は仕事が出来るという見られ方を目指すのか

そもそも論、なぜ人は仕事が出来ると思われたいのか。 これは簡単な話だが、端的にいうとその方が会社内、もっと広げると社会で生きていくために都合が良いからだと考える。

「仕事が出来る」という、曖昧な定義は敢えてそのままにしておく。

例えば会社を想像したときに、その状態は会社内での地位を守ってくれると考えることができる。 会社を構成するのは結局人間であり、人間が構成する社会というのは自然とヒエラルキーを構築することになるだろう。 ヒエラルキーが持つ一種の特性として、上にいけばいくほど過ごしやすくなることが多い。 それが例えば権力であったりもするだろう。 その法則に従って単純に考えればヒエラルキーの下に属していると、過ごしにくいことになる。 例えば、雑用を押し付けられたり、意見が通りにくかったりといった状態だ。

こういった状況を想像したときに、人間は潜在的に楽な方に進もうとする性質があるため「仕事が出来る」という状態を目指すのは自然のようにも思える。 また、ヒエラルキーの上にいくほど裁量権が増え、自己実現できる幅も増えるということを考えたら合理的な選択のようにも思える。 人生の半分以上の時間を仕事や自己実現のために費やす人が多い中で、その時間を少しでも自分が過ごしやすいようにしようと考えるのは自然の流れとして真っ当なことだと想像できるだろう。

2. 仕事ができる人間を目指した時の違和感

前章では人が仕事を出来る状態を目指すのは自然であり、合理的であるとすら述べたが、ときに少し前に流行った「意識高い系」という言葉で揶揄されるのは何故だろうか。 ここで明確にしておきたいのは、仕事が出来る人間を目指すことと、仕事ができることは全く別の話だということである。

「意識高い系」という揶揄は、「仕事が出来る人間」を目指すことを念頭に置いたときに現れる言動の違和感なのではないだろうか。

色々なメディアで擦られている気もするが、 仕事が出来る自分という状態を目指すのか、事業の成功を目指すのか何を軸としているのかで、その身からでる言動に影響を与えるだろう。 それは軸なので、隠そうと思ってもどこかで発現してしまうだろう。

2.1. 横文字とか

例えば、横文字を多様する人間などが真っ先に思い浮かぶ。 多くの場合横文字を使わないで伝わる場面が多いし、その道の権威の方は物事を説明するときに分かりやすい言葉で難しいことを言語化していることが多い気がする。 横文字は前提をスキップできるメリットがあることもあるが、一方で何のスキップにならない横文字も多い。よく見る例としては"アジェンダ"とかがそうなのかもしれないと思う。 私は最低限同じ業界のものなら万人に伝わるだろうという「知の共有が済んでいる」と思われる横文字は実はそんなに多くないと思っているたちだ。 横文字を多用する人は、その想像が足りないか、「この単語は最低限知っていないと仕事ができない人間だ」といったような一種の無意識で暗黙的な同調圧力を仕掛けてきているようにも捉えることができる。後者にいたっては事業に対して本質的ではないため、いよいよ危うい。

実際は英語が堪能すぎて自然と出てしまうパターンなど様々な可能性は否定しないが、分母が多いほうに合わせて会話したほうが色々円滑に進むということを想像すると合わせる努力をしたほうがいいだろう。

ただしここは塩梅が人によって違うので難しいことは否定しない。 私の言葉も人によっては無駄に横文字を使ってると捉えらえるかもしれないという保身もしておく。 結局は自分以外の誰かの主観で意識高いとラベルを貼られるので、自身の体感でそう言われることが多いかどうか次第なのだと思う。

2.2. 余裕感とか

また意識高いかどうかの一種の評価基準として、余裕がない人間に思われるとその傾向はあるかもしれない。 全力を出していそうで、余力がなさそうな状態。 物理的に余力がないという意味ではなく、あくまでも余裕がありそうに見えるどうかは大事な指標かもしれない。 抽象的で感覚的な部分が多いためこの例はこのあたりにしておく。

2.3. キャリア志向とか

種類は違うかもしれないが、自身のキャリアに興味がある、出世したいということが軸の人がいるかもしれない。 このパターンも似たような違和感を発現してしまう可能性が大いにありそうだ。

目指すべきところが自分の出世であった場合、自身のキャリアに繋がらないような行為は避けてしまうかもしれない。 わかりやすくいうと、行動がすべて保守的になる可能性があるしそういう人を見たことがある。

挑戦的な内容を選択して失敗するより、今の仕事の範囲の中で事業を回す方が失敗もなく、自身のキャリアにとって良いからだろう。 長期目線で行動している人と一緒に仕事をする場合、きっとそれは違和感として発現するだろう。

3. 意識高い系にならないために

前章で軽く触れたが、自分が仕事できる状態を目指すことが軸となっていると本質的ではない言動が違和感として発現してしまうと考えている。 プロジェクトの成功を第一の軸としている人間は、それだけに注力するので仕事をする上での違和感が少ないと考えている。

なぜ人は仕事が出来るという見られ方を目指すのかで前述した通り仕事ができるように見られたいという動きは潜在的に多かれ少なかれ持っていると仮定してみる。 その場合、考え方を変えれば意識高い系の違和感をを如何に取るかの手法として、プロジェクトの成功を第一の軸として動く人間になるように自己暗示するのは違和感から隠れるトンネルとして有用かもしれない。 結局その事業プロジェクトを通じて、本気で仕事をすることに変わりはなく結果的に自身の成長にもつながると考えてもみても良いと思う。

また本当はプロジェクトのことを第一に考えていても、特に新人の頃など保身のためにそういう状態になってしまっているかもしれない。 意識高い系と言われる状態は一種の自己防衛的な側面もあるとは思うが、それを装う場合にはしばしば無駄なエネルギーやストレスが自分に掛かっていることも意識すべきだとは思う。

3.1. 私の場合は

私の場合は、他人がどう自分を評価しようがどうでもいいという精神状態になるように意識している。 AIが時代とともに更なる発達を遂げて評価軸が人間から離れだすと通用しない考えだが、それまでは自分のことを評価してくるのも人間のため常に正しい評価が下るとは限らないと割り切っている。 そう考えることで、やりたいことだけに集中することができている気がするし、気が楽になったのを覚えている。 その代わりアピールはしないことになるので、評価が下がるかもしれない。 ただしそれは本質的ではない評価軸からの評価の可能性が高いので無視してよい。 むしろ変な期待値は低いほうが良いと思うし、自分が貢献する量は変わらないのなら、このスタンスの方がいいとすら思えてくる。

4. あとがき

技術的なエントリを書きたいが、エビデンスなど取ったりするために実際にサンプルコードを載せようとしたりすると時間が掛かってしまうのが悩み。 ふと思いついたこういうことを書くことによりアウトプットの習慣を作っていきたいという趣旨だが角が立ちそうな内容になってそうで怖い。

気軽に書こうと思ったら結局1時間以上掛かってしまって悩ましい。 説明が全然足りない気もしていて書き足りない感もあるが、それは文章力の問題かもしれないので切っておくのがよさそうだな。

今回は文章だけと決めてたので、.adoc ⇒ .html 変換してhtml貼り付けでいけるが、画像など埋め込むとなると、厳しそうだな。。。

4.1. 追記

Webページの左側に、目次を表示して、各見出しにスキップできるようにアウトライン込みのHTMLで出力していたが、縦型Displayで見た時に、本文に被ってしまっていたので廃止した。 想定していたよりasciidocで書くメリットが薄くなってきてる。