【问题标题】:Is it possible to use PowerMock to mock new file creation?是否可以使用 PowerMock 模拟新文件的创建?
【发布时间】:2013-04-16 11:01:53
【问题描述】:

我想介绍一个创建带有单元测试的文件的逻辑。是否可以模拟 File 类并避免实际创建文件?

【问题讨论】:

  • 这是个好问题。不值得被否决。
  • 你用 PowerMock 试过了吗? PowerMock 确实在方法内模拟了新对象的创建,所以应该可以工作。

标签: java powermock


【解决方案1】:

模拟构造函数,就像在这个示例代码中一样。 不要忘记将调用“new File(...)”的类放入@PrepareForTest

package hello.easymock.constructor;

import java.io.File;

import org.easymock.EasyMock;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.api.easymock.PowerMock;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;

@RunWith(PowerMockRunner.class)
@PrepareForTest({File.class})
public class ConstructorExampleTest {

    @Test
    public void testMockFile() throws Exception {

        // first, create a mock for File
        final File fileMock = EasyMock.createMock(File.class);
        EasyMock.expect(fileMock.getAbsolutePath()).andReturn("/my/fake/file/path");
        EasyMock.replay(fileMock);

        // then return the mocked object if the constructor is invoked
        Class<?>[] parameterTypes = new Class[] { String.class };
        PowerMock.expectNew(File.class, parameterTypes , EasyMock.isA(String.class)).andReturn(fileMock);
        PowerMock.replay(File.class); 

        // try constructing a real File and check if the mock kicked in
        final String mockedFilePath = new File("/real/path/for/file").getAbsolutePath();
        Assert.assertEquals("/my/fake/file/path", mockedFilePath);
    }

}

【讨论】:

    【解决方案2】:

    试试 PowerMockito

    import org.mockito.Mockito;
    import org.powermock.api.mockito.PowerMockito;
    import org.powermock.core.classloader.annotations.PrepareForTest;
    
    
    @PrepareForTest(YourUtilityClassWhereFileIsCreated.class)
    public class TestClass {
    
     @Test
     public void myTestMethod() {
       File myFile = PowerMockito.mock(File.class);
       PowerMockito.whenNew(File.class).withAnyArguments().thenReturn(myFile);
       Mockito.when(myFile.createNewFile()).thenReturn(true);
     }
    
    }
    

    【讨论】:

      【解决方案3】:

      我不确定是否可以,但是我有这样的需求,我通过创建一个FileService 接口解决了它。因此,您不是直接创建/访问文件,而是添加一个抽象。然后,您可以轻松地在测试中模拟此接口。

      例如:

      public interface FileService {
      
          InputStream openFile(String path);
          OutputStream createFile(String path);
      
      }
      

      然后在你的课堂上使用这个:

      public class MyClass {
      
          private FileService fileService;
      
          public MyClass(FileService fileService) {
              this.fileService = fileService;
          }
      
          public void doSomething() {
              // Instead of creating file, use file service
              OutputStream out = fileService.createFile(myFileName);
          }
      }
      

      在你的测试中

      @Test
      public void testOperationThatCreatesFile() {
          MyClass myClass = new MyClass(mockFileService);
          // Do your tests
      }
      

      这样,您甚至可以在没有任何模拟库的情况下对其进行模拟。

      【讨论】:

      • 正确。不能模拟的时候,把它包装在一个抽象(接口)中,然后模拟它。
      • 但是您正在更改真实代码以帮助测试,使用 EasyMock/PowerMock 可以避免这种情况
      • @CarlosHenriqueRodriguez 是的,你是。这是一件好事。编写可测试(通常)的代码可以减少代码中的耦合。您应该将测试代码视为架构的一部分。
      • 但即使是松散耦合的代码也需要比这更强大的东西。例如,如果您需要测试 FileServiceImpl 行为,则无论如何都需要模拟 File 构造函数。
      • 当然,我明白你的意思,我是在概括。但是,在那个级别,我会考虑使用集成测试来验证它,就像我会为执行数据库操作的类所做的那样。毕竟,即使没有模拟,创建和/或验证文件也非常简单。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-11-16
      相关资源
      最近更新 更多