我有一个Java类 - 通常的Singleton非常典型 - 像这样:
请注意:为了简洁起见,我在这里遗漏了"如果无效"逻辑,因为那不是我遇到的麻烦,我不想拥挤这个问题。
public class MySingleton
{
ObjectMapper mapper;
private MySingleton()
{
new MySingleton(new ObjectMapper())
}
private MySingleton(ObjectMapper mapper)
{
this.mapper = mapper;
}
private static final class Lazy
{
static final MySingleton INSTANCE = new MySingleton();
}
public static MySingleton getInstance()
{
return Lazy.INSTANCE;
}
}
现在 - 很棒 - 而且有效 - 但是,如果我想在单元测试中测试它怎么办...
我想模拟映射器 - 所以我可以做:
ObjectMapper mockObjectMapper = mock(ObjectMapper.class)
但是,当我需要以某种方式调用" mysingleton"的构造函数以进行测试...
时我该怎么做 - 鉴于我的测试课,我知道它会说" Mysingleton(这里的参数)在Mysingleton中具有私人访问权限"?
单例是可测试代码的敌人。答案中给出的链接是关于与单人的邪恶以及为什么以及如何避免它们的邪恶的出色论点。
您可以使用 PowerMock 使用constructMapper使用ConstructMapper。
http://benkiefer.com/blog/2013/04/23/powermockito-constructor-mocking/
我必须修改您的示例Singleton,以使构造函数正确链接。
public class MySingleton {
ObjectMapper mapper;
private MySingleton()
{
//This does not work.
//new MySingleton(new ObjectMapper());
this(new ObjectMapper());
}
private MySingleton(ObjectMapper mapper)
{
this.mapper = mapper;
}
private static final class Lazy
{
static final MySingleton INSTANCE = new MySingleton();
}
public static MySingleton getInstance()
{
return Lazy.INSTANCE;
}
}
我还固定了objectmapper类。
public class ObjectMapper {
//Empty Sample uses default CTR
}
我能够使用先前列出的链接中的说明进行测试:
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
@RunWith(PowerMockRunner.class)
@PrepareForTest(MySingleton.class)
public class MySingletonTest {
@Test
public void testSingletonCtr() throws Exception {
ObjectMapper mapper = new ObjectMapper();
PowerMockito.whenNew(ObjectMapper.class).withNoArguments().thenReturn(mapper);
Assert.assertEquals(MySingleton.getInstance().mapper, mapper);
}
}
我正在一个Maven项目中这样做。我需要在测试范围中添加以下依赖项:
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-core</artifactId>
<version>1.6.5</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-module-junit4-rule</artifactId>
<version>1.6.5</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-api-mockito</artifactId>
<version>1.6.5</version>
<scope>test</scope>
</dependency>
我确实同意单例倾向于长期引起代码维护和可伸缩性的问题。如果您有能力寻找解决问题的替代方法,那么这样做可能会使您受益。如果不是,那么我相信 powermock 实用程序将为您提供所需的功能。
最佳幸运。