静态模拟不起作用

时间:2013-02-19 20:28:13

标签: java static junit mockito powermock

我有以下示例单元测试试图模拟java.nio.file.Files但这个模拟不起作用,代码试图删除示例路径。

@Test
    public void testPostVisitDirectory() throws Exception {
        Path mockedPath = Paths.get("sample path");
        PowerMockito.mockStatic(Files.class);
        PowerMockito.doNothing().when(Files.class,
                PowerMockito.method(Files.class, "delete", Path.class));

        DeleteDirVisitor visitor = new DeleteDirVisitor(false);
        Assert.assertEquals("The was a problem visiting the file",
                FileVisitResult.CONTINUE,
                visitor.postVisitDirectory(mockedPath, null));
    }

知道出了什么问题吗?

这是方法visitor.postVisitDirectory

的内容
[...]
if (e == null) {
            Files.delete(dir);
            return FileVisitResult.CONTINUE;
        }
[...]

谢谢,

3 个答案:

答案 0 :(得分:4)

你添加了

吗?
@RunWith(PowerMockRunner.class)
@PrepareForTest(Files.class)

到包含该方法的junit测试类?

参见powermock docs,写作测试部分。

修改

嗯,看起来你做的一切都很正确。这就是我正在运行的:

import java.io.IOException;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.SimpleFileVisitor;

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(Files.class)
public class TestVisitor {
  public class PrintingVisitor extends SimpleFileVisitor<Path> {
    @Override
    public FileVisitResult postVisitDirectory(final Path dir, final IOException exc) throws IOException {
      Files.delete(dir);
      return FileVisitResult.CONTINUE;
    }
  }

  @Test
  public void testPostVisitDirectory() throws Exception {
    final Path mockedPath = Paths.get("sample path");

    /* Mocking */
    PowerMockito.mockStatic(Files.class);
    PowerMockito.doNothing().when(Files.class, PowerMockito.method(Files.class, "delete", Path.class));
    /* End Mocking */

    final PrintingVisitor visitor = new PrintingVisitor();
    Assert.assertEquals("The was a problem visiting the file", FileVisitResult.CONTINUE, visitor.postVisitDirectory(mockedPath, null));
  }
}

如果我注释掉标记为Mocking的部分,我会得到NoSuchFileException。如果我离开它,测试通过。

也许发布产生错误的完整示例?

答案 1 :(得分:4)

我有一个类似的问题,使用powermock 1.5.1和Files类,并怀疑它有一个问题静态模拟一些/所有jdk1.7类,虽然我不知道为什么。我还检查了javassist版本,当时它是最新的(3.18.0-GA),

我将测试中的课程剥离到了“文件”行,但仍然无法正常工作。然后我决定尝试模拟另一个静态类StringUtils.chop(“string”); (commons-lang3)然后我的powermock测试工作,我能够强制它从模拟生成异常。

这证明了我已经完成了本书的所有内容,并且静态模拟在Files类上不起作用,但它在StringUtils上完成。

顺便说一下,我改变了@PrepareForTest和PowerMockito.mockStatic()调用引用正确的类。

最后我放弃了嘲弄文件。如果其他人遇到同样的问题,只需要提醒。

修改。搞定了:我已经尝试了这个,因为我在另一个项目中需要它。还有更新版本的PowerMock out(1.5.3),它使用更新的javassist(3.18.1-GA)来修复我在回复另一条评论时提到的错误。

即使您正在测试的类没有公开静态方法,我也可以通过将测试中的类添加到Files以及@PrepareForTest来不断地模拟Files。对于其他静态模拟,我之前不需要这样做。我不知道为什么它需要或以Files的方式工作。

示例:

public class MyTestClass {

    public void justToTestMocking(Path path) throws IOException {
        if (!Files.exists(path)) {
            throw new IllegalArgumentException("I know there is a deleteIfExists() but I am just testing mocking");
        }
        Files.delete(path);
    }
}

以下测试:

@RunWith(PowerMockRunner.class)
@PrepareForTest({Files.class, MyTestClass.class})
public class MyTestClassTest {

    @Before
    public void setUp() {
        mockStatic(Files.class);

    }        

    @Test
    public void justToTestMocking_WillDeletePath() throws IOException {
        Path path = mock(Path.class);
        MyTestClass test = new MyTestClass();

        when(Files.exists(path)).thenReturn(true);

        test.justToTestMocking(path);

        verifyStatic();
        Files.delete(path);
    }
}

答案 2 :(得分:1)

我遇到了类似的问题,结果发现它与准备正确的课程有关。

在上面的示例中,测试的类已经在“prepareFor-Scope”中,因为它是测试类的内部类。

你必须将类添加到调用静态方法的@PrepareForTest ...在我的情况下这些是不够的,因为访问Files.delete的代码是在一个无法明确的匿名类中的准备。

我将匿名类命名为@PrepareForTest,并且一切正常