Spring Boot 2.1でJUnit 5.5を使用する

testCompile 'org.springframework.boot:spring-boot-starter-test'

を以下の通り変更する。

testCompile('org.springframework.boot:spring-boot-starter-test') {
   exclude module: 'junit'
}

さらに、以下の行を追加する。

testImplementation 'org.junit.jupiter:junit-jupiter-api'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine'

なお、Spring Boot 2.2からはJUnit 5.5が標準になったので、上記の対応は不要となる。

Coverallsをopenjdk11環境で使用する

ビルド環境をopenjdk11に変更したら、coveralls-maven-pluginが落ちてしまって、Coverallsのカバレッジが更新されなくなっていた。

coveralls-maven-pluginに以下の依存関係を追加することで回避することが出来る。

<dependencies>
    <dependency>
        <groupId>javax.xml.bind</groupId>
        <artifactId>jaxb-api</artifactId>
        <version>2.3.1</version>
    </dependency>
</dependencies>

本家がJava11に対応してくれるのが一番良いのだが、忙しいみたいでいつ対応されるかわからない。

Travis CIでMySQL 5.7

Travis CIのMySQLが5.7になって、Timestamp型の0は許容しなくなった。
そこで、.travis.ymlファイルのbefore_scriptの1行目に「set global sql_mode = ”」を追記した。

before_script:
 - mysql -e "set global sql_mode = ''"
 - mysql -uroot -e "create database crawler"
 - mysql -uroot crawler < src/config/schema.sql

Jenkinsで自動デプロイ

※2022/05/05追記:Mavenでデプロイするのではなく、Jenkinsのプラグインを使用してデプロイする方法はこちら

Jenkinsから自動的にTomcatへデプロイする。

  • Tomcat側の設定
    1. apache-tomcat-8.5.28/conf/tomcat-users.xmlを以下の通り編集する。
<tomcat-users xmlns="http://tomcat.apache.org/xml" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemalocation="http://tomcat.apache.org/xml tomcat-users.xsd" version="1.0">
    <role rolename="manager-script">
        <user username="任意のユーザ名" password="パスワード" roles="manager-script">
        </user>
    </role>
</tomcat-users>
  • Jenkins側の設定
    1. 実行ユーザの/.m2/settings.xmlを以下の通り編集する。
    2. プロジェクトの設定を開き、Mavenのゴールの設定に「tomcat7:redeploy」を追記する。
<settings>
    <servers>
        <server>
            <id>tomcat-localhost</id>
            <username>任意のユーザ名</username>
            <password>パスワード</password>
        </server>
    </servers>
</settings>

ユーザ名、パスワードはTomcatの設定と合わせること。

  • Maven側の設定
    1. pom.xmlに以下を追記する。
<plugin>
    <groupid>org.apache.tomcat.maven</groupid>
    <artifactid>tomcat7-maven-plugin</artifactid>
    <version>2.2</version>
    <configuration>
        <path>/common</path>
        <server>tomcat-localhost</server>
        <url>http://localhost:8080/manager/text</url>
    </configuration>
</plugin>

serverはsettings.xmlのidと合わせること。

Thymeleafを試す

Thymeleafはテンプレートの一種。
Springとの相性が良く簡単に使用出来る。

・top.html

<html xmlns="http://www.w3.org/1999/xhtml"
    xmlns:th="http://www.thymeleaf.org"
    xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
    <p th:text="Hello, Thymeleaf!">Hello, hide6644!</p>
</body>
</html>

View Resolverを設定する。

<!-- View Resolver for Thymeleaf -->
<bean id="templateResolver" class="org.thymeleaf.spring4.templateresolver.SpringResourceTemplateResolver">
    <property name="prefix" value="/WEB-INF/pages/" />
    <property name="suffix" value=".html" />
    <property name="templateMode" value="HTML" />
    <property name="cacheable" value="false" />
</bean>
 
<bean id="templateEngine" class="org.thymeleaf.spring4.SpringTemplateEngine">
    <property name="templateResolver" ref="templateResolver" />
    <property name="enableSpringELCompiler" value="true" />
</bean>
 
<bean class="org.thymeleaf.spring4.view.ThymeleafViewResolver">
    <property name="templateEngine" ref="templateEngine" />
    <property name="characterEncoding" value="UTF-8" />
    <property name="order" value="4" />
</bean>

Veiwを呼び出す。

@RequestMapping(value = "top", method = RequestMethod.GET)
public String topRequest() {
    return "top";
}

[YOMOU CRAWLER] 第1回 データモデルを考える

データモデルを考える


小説自体を表すデータモデルと、小説の管理に使用する付随情報がある。
それと、更新履歴を表すクラスがある。

  1. 小説として必要な要素
    • 小説のタイトル
    • 小説の作者
    • 小説の目次
    • 小説の章のタイトル
    • 小説の章の本文
  2. 更新を確認するために必要な要素
    • 小説の更新日時
    • 小説の更新を確認した日時
    • 小説が完結したか
    • 小説の章の更新日時
    • 小説の章の更新を確認した日時
    • 小説の章の更新後、既読になったか
    • 小説の章の更新後、既読になった日時

YOMOU CRAWLERについて

小説を読もう!の更新を自動でチェックしたかったのだが、自分の好みに合ったサービスがなかった。
じゃあ、自分で作っちゃえってことで以下の通り。

  1. 主要機能
    • 小説の各話の登録更新状況をメールで通知する
    • 更新チェックではアクセス頻度を減らしサーバーに負荷を掛けないようにする
    • 小説が消されても、後で読めるように更新チェックと同時に、更新内容を保存する
  2. 稼働環境
    • 言語:Java11
    • データベース:MySQL
  3. 副題
    • Hibernateを学ぶ
    • オブジェクト指向を学ぶ
  4. 参考情報(小説を読もう!のページの構造)
    • 小説のトップページにはタイトル、作者名、概要、目次がある
    • 目次のリンクからは各話に遷移出来る
    • 各話にはタイトルと本文がある
  5. 詳細機能
    • htmlを取得しパースする
    • メール送信する

JenkinsとGithubの連携

※2022/05/05追記:jenkinsの設定方法も含めた、2022年現在の連携方向を参照したい場合はこちら

Githubにpushされたら、Jenkinsのビルドを起動したい。

  • Github側の設定
    1. SettingsのIntegrations & servicesを開き、
      Add ServiceからJenkins (Git plugin)を選択する。

    2. 表示された「Jenkins url」に「http://~ホスト名~/jenkins/github-webhook/」と入力する。

  • Jenkins側の設定
    1. GitHub pluginをインストールする。
      GitHub plugin

    2. ジョブの設定の「GitHub hook trigger for GITScm polling」にチェックを入れる。

PowerMockitoでUnit Test

下記のインスタンスを生成する部分をMockにしたい。

NovelSource novelSource = new NovelSource(url);

そこで、PowerMockitoを使用してみる。

<!-- https://mvnrepository.com/artifact/org.powermock/powermock-api-mockito -->
<dependency>
    <groupId>org.powermock</groupId>
    <artifactId>powermock-api-mockito</artifactId>
    <version>1.6.6</version>
</dependency>

使用方法はこんな感じ。

@RunWith(PowerMockRunner.class)
@PrepareForTest({ NovelManagerImpl.class })
@PowerMockIgnore("javax.management.*")
public class NovelManagerImplTest extends BaseManagerMockTestCase {
    @Mock
    private NovelSource novelSource;
 
    @Mock
    private Logger log;
 
    @Mock
    private NovelDao novelDao;
 
    @Mock
    private NovelInfoManager novelInfoManager;
 
    @Mock
    private NovelChapterManager novelChapterManager;
 
    @InjectMocks
    private NovelManagerImpl novelManager = new NovelManagerImpl();
 
    @Test
    public void testAdd() throws Exception {
        String fileName = this.getClass().getClassLoader().getResource("novel/20160924/test.html").getPath();
        File file = new File(fileName);
        String url = "http://www.foo.bar/20160924/";
        NovelSource novelSource = new NovelSource(new Source(file));
 
        {
            // 初期化
            MockitoAnnotations.initMocks(this);
            // NovelSourceをnewするとき、thenReturn(~)のインスタンスを返却する
            PowerMockito.whenNew(NovelSource.class).withArguments(url).thenReturn(novelSource);
        }
    }

コンストラクタに引数を渡したいときは、withArguments()を使用する。

しかし、カバレッジが測定出来ないので注意。