【Mockito】モック対象にfinal修飾子があるとモックにならない場合がある

### 【概要】
モック対象にfinal修飾子があるとモックにならない場合があります。
具体的なコードで説明していきます。

### 【環境】
Java 11
JUnit 5.10.0
Mockito 5.5.0

### 【コード】

https://github.com/nobu12/mock-final-exception

下記コードは上記GitHubにアップロードしているコードと同じです。
本コードでのモック対象はHogeクラスのhugaフィールドとなります。

```java:Hoge.java
package org.example;

public class Hoge {
    private Huga huga;
    // final修飾子を付けるとテスト失敗する
//    private final Huga huga;
    private final Piyo piyo;

    public Hoge(final Huga huga, final Piyo piyo) {
        this.huga = huga;
        this.piyo = piyo;
    }

    public String hoge() {
        return huga.huga() + piyo.piyo();
    }
}

```

```java:Huga.java
package org.example;

public class Huga {
    public String huga() {
        return "huga";
    }
}
```

```java:Piyo.java
package org.example;

public class Piyo {
    public String piyo() {
        return "piyo";
    }
}
```

```java:HogeTest.java
package org.example;

import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.doReturn;

public class HogeTest {
    private AutoCloseable closeable;

    @InjectMocks
    private Hoge hoge = new Hoge(new Huga(), new Piyo());
    @Mock
    private Huga huga;

    @BeforeEach
    void setUp() {
        closeable = MockitoAnnotations.openMocks(this);
    }

    @AfterEach
    void tearDown() throws Exception {
        closeable.close();
    }

    @Test
    void 文字列が連結されていること() {
        doReturn("test").when(huga).huga();
        assertEquals("testpiyo", hoge.hoge());
    }
}
```

### 【テスト結果】

#### final修飾子がない場合

GitHubにアップロードされているコードのままだと、テスト成功します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/121997/fad777b9-65c5-e673-64c9-e266c308b556.png)


#### final修飾子がある場合

下記のようにfinal修飾子がある宣言の方をコメントアウトしてからテスト実行すると、テスト失敗します。

```java:Hoge.javaの一部抜粋
//    private Huga huga;
    // final修飾子を付けるとテスト失敗する
    private final Huga huga;
    private final Piyo piyo;
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/121997/2725f342-d08f-231f-b725-ad87c7b17dcc.png)

```text:エラーメッセージ
org.opentest4j.AssertionFailedError: 
予想:testpiyo
実際:hugapiyo
<クリックで差分を表示>


	at org.junit.jupiter.api.AssertionFailureBuilder.build(AssertionFailureBuilder.java:151)
	at org.junit.jupiter.api.AssertionFailureBuilder.buildAndThrow(AssertionFailureBuilder.java:132)
	at org.junit.jupiter.api.AssertEquals.failNotEqual(AssertEquals.java:197)
	at org.junit.jupiter.api.AssertEquals.assertEquals(AssertEquals.java:182)
	at org.junit.jupiter.api.AssertEquals.assertEquals(AssertEquals.java:177)
	at org.junit.jupiter.api.Assertions.assertEquals(Assertions.java:1141)
	at org.example.HogeTest.文字列が連結されていること(HogeTest.java:34)
	at java.base/java.lang.reflect.Method.invoke(Method.java:566)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1541)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1541)


プロセスは終了コード -1 で終了しました
```

### 【なぜfinal修飾子があるとテスト失敗するのか考察】

テスト実行の流れ
①`private Hoge hoge = new Hoge(new Huga(), new Piyo());
`の`new Huga()`によってインスタンスが`huga`変数に設定される。
②final修飾子により再代入することができないため、`huga`変数はモックにはなれない。

テスト失敗結果に「実際:hugapiyo」と出力されているので、`new Huga()`のインスタンスを使っておりモックで設定した返却値を使わないのでテスト失敗します。