私は以下のENUmクラスのJUNITテストケースの作成に取り組んでいます。以下のクラスは、コードを実行している現在のマシンのホスト名のみを提供します。 JUNITテストを書いているときに、以下のクラスをモックして、いつでもgetHostName()
メソッドを変更して、getDatacenter()
を呼び出すたびに返すことができるようにするにはどうすればよいですか。私がそれをあざけることによって渡すどんなホスト名でも。パラメータ化されたものにしたくありません。
ホスト名をモックしながら変更しながら、特定のケースをテストしたいだけです。
public enum DatacenterEnum {
DEV, DC1, DC2, DC3;
public static String forCode(int code) {
return (code >= 0 && code < values().length) ? values()[code].name() : null;
}
private static final String getHostName() {
try {
return InetAddress.getLocalHost().getCanonicalHostName().toLowerCase();
} catch (UnknownHostException e) {
s_logger.logError("error = ", e);
}
return null;
}
public static String getDatacenter() {
return getHostName();
}
}
データセンターインターフェイスを作成し、列挙型にインターフェイスを実装させることができます。これにより、モックがより簡単になります。
何よりも、最初から構成情報を列挙型に配置することはしません。他のデータセンターを追加する必要がある場合(またはデータセンターの構成を変更する場合)は、コードを再コンパイルする必要があります。たとえば、JavaプロパティファイルまたはXMLファイル)などの通常のクラス読み取りに構成を配置することを検討してください(この関数は、フレームワークにすでに実装されている可能性があります)。
これが不可能な場合は、「darkes reflaction」マジックを使用して、列挙型のフィールドを必要な値に変更できます。
可能ですが、これは非推奨です。コードをリファクタリングすることをお勧めします。
@RunWith(PowerMockRunner.class)
@PrepareForTest(DatacenterEnum.class)
public class DatacenterEnumTest {
@Mock
InetAddress inetAddress;
@Test
public void shouldReturnDatacenter() throws UnknownHostException {
//given
mockStatic(InetAddress.class);
given(inetAddress.getCanonicalHostName()).willReturn("foo");
given(InetAddress.getLocalHost()).willReturn(inetAddress);
//when
String datacenter = DatacenterEnum.getDatacenter();
//then
assertThat(datacenter).isEqualTo("foo");
}
}
JMockitを使えば簡単です。
_@Test
public void mockInetAddress(@Cascading final InetAddress inetAddress)
{
new NonStrictExpectations() {{
inetAddress.getCanonicalHostName(); result = "foo";
}};
String datacenter = DatacenterEnum.getDatacenter();
assertEquals("foo", datacenter);
}
_
もちろん、列挙型のgetHostName()
メソッドをモックすることもできますが、private
メソッドをモックすることは避けるのが最善です。
私は古い学校かもしれませんが、クラスローダーのハックを使用するのではなく、テスト対象のコードを実際にリファクタリングしたいと思います。何かのようなもの:
public enum DatacenterEnum {
DEV, DC1, DC2, DC3;
static String hostName = InetAddress.getLocalHost().getCanonicalHostName().toLowerCase();
public static String getHostName() {
return hostName;
}
}
テストを実行する前に、テストコードで次のことを行います。
DataCenterEnum.hostName = "foo";
これは、Mockito/Powermockでそれを行うことができる方法です。 Mockitoは静的な方法をモックできないため、Powermockが必要です。
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import static org.junit.Assert.assertEquals;
import static org.powermock.api.mockito.PowerMockito.mockStatic;
import static org.powermock.api.mockito.PowerMockito.when;
@RunWith(PowerMockRunner.class)
@PrepareForTest({DatacenterEnum.class})
public class DatacenterEnumTest {
@Test
public void testGetDatacenter() {
mockStatic(DatacenterEnum.class);
when(DatacenterEnum.getDatacenter()).thenReturn("YourHostname");
String datacenter = DatacenterEnum.getDatacenter();
assertEquals("YourHostname", datacenter);
}
}
Mavenの依存関係
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-api-mockito</artifactId>
<version>1.5.2</version>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-module-junit4</artifactId>
<version>1.5.2</version>
</dependency>
</dependencies>