我有一个AbstractDao类,我在其中实例化Rest Fore API。我无法在Power Mock中模拟新的forceAPI(config)。请建议。
@RunWith(BlockJUnit4ClassRunner.class)
public class SalesForceDaoImplTest {
@InjectMocks
private SalesForceDaoImpl salesForceDao;
@Mock
private ForceApi forceApiMock;
@Mock
private ApiConfig apiConfigMock;
@Mock
private Configuration configMock;
@Mock
JsonObject jsonobject;
@Before
public void setup() {
initMocks(this);
when(configMock.getAppConfiguration()).thenReturn(jsonobject);
when(jsonobject.getString(anyString())).thenReturn("test");
when(salesForceDao.getForceAPI()).thenReturn(forceApiMock);
when(new ApiConfig()).thenReturn(apiConfigMock);
when(new ForceApi(apiConfigMock)).thenReturn(forceApiMock);
}
我试图以这种方式做,但它不起作用。 我的DAO类正在扩展抽象DAO类
public void checkPrinterStatus(){
try {
logger.info("Check -------------- ");
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
PrintService printer = configParamPrintService.getPrintService();
logger.info("State " + printer.isAttributeCategorySupported(PrinterState.class));
Set<Attribute> attributes = getAttributes(printer);
for(Attribute attr : attributes){
logger.info(attr.getName());
}
}
public static Set<Attribute> getAttributes(PrintService printer) {
Set<Attribute> set = new LinkedHashSet<Attribute>();
//get the supported docflavors, categories and attributes
Class<? extends Attribute>[] categories = (Class<? extends Attribute>[]) printer.getSupportedAttributeCategories();
DocFlavor[] flavors = printer.getSupportedDocFlavors();
AttributeSet attributes = printer.getAttributes();
//get all the avaliable attributes
for (Class<? extends Attribute> category : categories) {
for (DocFlavor flavor : flavors) {
//get the value
Object value = printer.getSupportedAttributeValues(category, flavor, attributes);
//check if it's something
if (value != null) {
//if it's a SINGLE attribute...
if (value instanceof Attribute)
set.add((Attribute) value); //...then add it
//if it's a SET of attributes...
else if (value instanceof Attribute[])
set.addAll(Arrays.asList((Attribute[]) value)); //...then add its childs
}
}
}
return set;
}
答案 0 :(得分:0)
可能这是一个迟到的回复,但我相信它对我们这些程序员来说仍然有用。
免责声明:我从未与PowerMockito合作,但我已经使用过PowerMock 至于troig的建议: PowerMock驱动的单元测试假定您将使用专用的跑步者运行:
@RunWith(PowerMockRunner.class)
在这种情况下,这与问题中陈述的@RunWith(BlockJUnit4ClassRunner.class)
冲突,因此RunWith的“插槽”已被占用。
这个特殊的版本仍然可以通过运行最新版本的power mock作为JUnit规则来解决(我假设你运行JUnit)你可以找到一个这样做的例子here 但最重要的是,这是power mock的已知问题之一。
还有其他问题基本上让我得出结论,应该避免使用power mock,不应该在新项目中使用(以及Power Mockito):
使用power mock的单元测试速度很慢(比使用EasyMock要慢得多,如果可以使用它重写)
Power Mock有时会使用与jacoco代码覆盖等工具不兼容的字节代码,因此声纳不包括使用power mock测试的单元类别,或者至少做错了
负责在maven中运行测试的Surefire插件具有并行运行多个单元测试的功能。有时用电源嘲笑它是不可能的。
甚至IntelliJ有时也无法运行包含电源模拟测试的套装。
但最重要的是,当你必须使用像power mock这样的工具时,代码可能(并且应该)被重构为更干净和易于理解。关于你的具体问题:
你的班级违反了编码原则,即该班级不应该关注自己的依赖性。这里DAO实际上“构造”并配置另一个(外部)服务供以后使用。
我建议你观看Misko Hevery about clean code的精彩演讲,以便更好地理解我的意思
再次,在你的例子中。将ForceApi
维护为依赖注入框架构建的依赖项要好得多(我发现你已经使用@Inject
,所以你走的是正确的轨道)
看看这个实现:
public abstract class AbstractDao {
@Inject // this one is constructed and injected by your favorite DI framework in real use cases
private ForceApi forceApi;
public void doSomething() {
// do your dao stuff here
forceApi.callSomeAPIMethod();
// do your dao stuff here
}
}
现在进行单元测试你不再需要电源模拟了。它足以根据情况使用简单的Mock甚至Stub。您所需要的只是提供一个构造函数,该构造函数将采用类型为ForceApi
的参数或者可能是一个setter(您可以考虑将其设置为私有,以便没有人能够在测试之外调用它)。
我没有提供足够的信息,但我提供的设计可能无需为DAO设置一个Abstract类,这在某些情况下也会有所帮助,因为继承有时可能是维持相当重的“义务”(至少考虑一下)。也许在这种情况下,继承只是为了支持这种getForceAPI
行为。在这种情况下,随着项目的增长,可能会在这个AbstractDAO中添加一些方法,因为它很方便,但这些方法将“透明地”添加到所有DAO的整个层次结构中。这种结构变得脆弱,因为如果至少有一种方法改变了它的实现,DAO的整个层次结构可能会失败。
希望这有帮助