如何创建内存中的 JarFile?

发布于 2024-11-18 21:13:12 字数 1193 浏览 13 评论 0原文

我正在尝试编写一个如下函数:

public Map<String, Document> getTestXml(JarFile jarFile) {
    Map<String, Document> result = Maps.newHashMap();

    Enumeration<JarEntry> jarEntries = jarFile.getEntries();
    while (jarEntries.hasMoreElements()) {
        JarEntry jarEntry = jarEntries.nextElement();

        String name = jarEntry.getName();
        if (name.endsWith(".class") && !name.contains("$")) {
            String testClassName = name.replace(".class", "").replace("/", ".");
            String testXmlFilename = "TEST-" + testClassName + ".xml";

            InputStream testXmlInputStream = testJarFile.getInputStream(
                    testJarFile.getJarEntry(testXmlFilename));

            DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
            DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
            Document testXmlDocument = documentBuilder.parse(testXmlInputStream);

            result.put(testClassName, testXmlDocument);
        }
    }

    return result;
}

我想编写一个单元测试,该测试实际上并不在文件系统上创建 JarFile。我试图寻找如何在内存中创建 File 对象,但没有找到类似的东西。有人有什么建议吗?

I'm trying to write a function like:

public Map<String, Document> getTestXml(JarFile jarFile) {
    Map<String, Document> result = Maps.newHashMap();

    Enumeration<JarEntry> jarEntries = jarFile.getEntries();
    while (jarEntries.hasMoreElements()) {
        JarEntry jarEntry = jarEntries.nextElement();

        String name = jarEntry.getName();
        if (name.endsWith(".class") && !name.contains("$")) {
            String testClassName = name.replace(".class", "").replace("/", ".");
            String testXmlFilename = "TEST-" + testClassName + ".xml";

            InputStream testXmlInputStream = testJarFile.getInputStream(
                    testJarFile.getJarEntry(testXmlFilename));

            DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
            DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
            Document testXmlDocument = documentBuilder.parse(testXmlInputStream);

            result.put(testClassName, testXmlDocument);
        }
    }

    return result;
}

And I would like to write a unit test that doesn't actually create a JarFile on the file system. I've tried to look for how to create a File object in memory, but haven't found anything like that. Anyone have any suggestions?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

蛮可爱 2024-11-25 21:13:12

使用 JarInputStream 代替 JarFile。为了进行测试,将 JarInputStream 连接到加载了内存中 jar 数据的 ByteArrayInputStream,并在正常操作中将其连接到文件的输入流。

Instead of a JarFile, use a JarInputStream. For testing, hook the JarInputStream up to a ByteArrayInputStream loaded with in-memory jar data, and in normal operation hook it up to the input stream from a file.

遥远的她 2024-11-25 21:13:12

File() 对象都存在于某个文件系统名称空间中。这给了你两个基本选择:

1)。如果您使用带有 tempfs 文件系统的操作系统,请在那里创建它。
2)。使用 File.createTempFile() 并设置退出时删除属性。

创建子类的常用方法(“public MemoryFile extends File”...)不起作用,因为 File() 对象不包含执行实际 I/O 的方法,仅用于保存该子类的名称对象并执行一些文件系统操作。

File() objects all live within some file system name space. Which gives you two basic choices:

1). If you're using an O/S with a tempfs file system, create it there.
2). Use File.createTempFile() and set the delete-on-exit attribute.

The usual approach of creating a sub-class ("public MemoryFile extends File" ...) doesn't work because a File() object doesn't contain the methods for doing actual I/O, just for holding the name of the object and doing a few file system operations.

长发绾君心 2024-11-25 21:13:12

您需要查看 ByteArrayOutputStreamByteArrayInputStream。这些是 Java 中的内存流对象。使用它们,什么都不会写入磁盘。

You need to look at ByteArrayOutputStream and ByteArrayInputStream. Those are the in memory stream objects in Java. Use those and nothing will get written to disk.

梦情居士 2024-11-25 21:13:12

您可以使用 EasyMock 创建 JarFile 类的模拟对象。对于模拟对象,您可以指定在测试中调用哪些方法以及返回值是什么,而无需在文件系统上实际创建 JAR 文件。

然后使用模拟 JarFile 实例调用 getTestXml() 方法。

它需要一些时间来适应,但随后你就会发现这是值得的。

更新
给定的源代码无法编译,因此这里是一个可编译的版本:

public class JarFileUser {
  public Map<String, Document> getTestXml(JarFile jarFile) throws IOException, ParserConfigurationException, SAXException {
    Map<String, Document> result = new HashMap<String, Document>();

    Enumeration<JarEntry> jarEntries = jarFile.entries();
    while (jarEntries.hasMoreElements()) {
      JarEntry jarEntry = jarEntries.nextElement();

      String name = jarEntry.getName();
      if (name.endsWith(".class") && !name.contains("$")) {
        String testClassName = name.replace(".class", "").replace("/", ".");
        String testXmlFilename = "TEST-" + testClassName + ".xml";

        InputStream testXmlInputStream = jarFile.getInputStream(jarFile.getJarEntry(testXmlFilename));

        DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
        DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
        Document testXmlDocument = documentBuilder.parse(testXmlInputStream);

        result.put(testClassName, testXmlDocument);
      }
    }

    return result;
  }
}

这是使用 EasyMock 进行的测试:

public class JarFileUserTest {

  private JarFile mockJarFile;
  private Enumeration<JarEntry> mockJarEntries;

  private JarFileUser jarFileUser;
  private JarEntry first;
  private JarEntry second;
  private JarEntry firstXml;

  @Before
  public void setUp() throws Exception {
    jarFileUser = new JarFileUser();

    // Create a mock for the JarFile parameter
    mockJarFile = createMock(JarFile.class);

    // User Vector to provide an Enumeration of JarEntry-Instances 
    Vector<JarEntry> entries = new Vector<JarEntry>();
    first = createMock(JarEntry.class);
    second = createMock(JarEntry.class);

    entries.add(first);
    entries.add(second);

    expect(first.getName()).andReturn("mocktest.JarFileUser.class");
    expect(second.getName()).andReturn("mocktest.Ignore$Me.class");

    mockJarEntries = entries.elements();

    expect(mockJarFile.entries()).andReturn(mockJarEntries);

    // JarEntry for the XML file
    firstXml = createMock(JarEntry.class);

    expect(mockJarFile.getJarEntry("TEST-mocktest.JarFileUser.xml")).andReturn(firstXml);

    // XML contents
    ByteArrayInputStream is = new ByteArrayInputStream("<test>This is a test.</test>".getBytes("UTF-8"));
    expect(mockJarFile.getInputStream(firstXml)).andReturn(is);

    replay(mockJarFile);
    replay(first);
    replay(second);
    replay(firstXml);
  }

  @Test
  public void testGetTestXml() throws IOException, ParserConfigurationException, SAXException {
    Map<String, Document> map = jarFileUser.getTestXml(mockJarFile);
    verify(mockJarFile);
    verify(first);
    verify(second);
    verify(firstXml);

    assertEquals(1, map.size());
    Document doc = map.get("mocktest.JarFileUser");
    assertNotNull(doc);
    final Element root = (Element) doc.getDocumentElement();
    assertNotNull(root);
    assertEquals("test", root.getNodeName());
    assertEquals("This is a test.", root.getTextContent());
  }

}

有关附加库的注意事项
JarFile 是一个类,而不是一个接口,因此根据 EasyMock 安装文档,您应该有 Objenesiscglib 在你的类路径中。

You can use EasyMock to create a mock object of class JarFile. For the mock object you specify which methods are called in the test and what the return values are without the need to actually create a JAR file on the file system.

Then call your getTestXml() method with your mock JarFile instance.

It needs some time to get used to it, but then you will see it's worth the effort.

Update
The given source code doesn't compile, so here is a compilable version:

public class JarFileUser {
  public Map<String, Document> getTestXml(JarFile jarFile) throws IOException, ParserConfigurationException, SAXException {
    Map<String, Document> result = new HashMap<String, Document>();

    Enumeration<JarEntry> jarEntries = jarFile.entries();
    while (jarEntries.hasMoreElements()) {
      JarEntry jarEntry = jarEntries.nextElement();

      String name = jarEntry.getName();
      if (name.endsWith(".class") && !name.contains("$")) {
        String testClassName = name.replace(".class", "").replace("/", ".");
        String testXmlFilename = "TEST-" + testClassName + ".xml";

        InputStream testXmlInputStream = jarFile.getInputStream(jarFile.getJarEntry(testXmlFilename));

        DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
        DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
        Document testXmlDocument = documentBuilder.parse(testXmlInputStream);

        result.put(testClassName, testXmlDocument);
      }
    }

    return result;
  }
}

Here is a test with EasyMock:

public class JarFileUserTest {

  private JarFile mockJarFile;
  private Enumeration<JarEntry> mockJarEntries;

  private JarFileUser jarFileUser;
  private JarEntry first;
  private JarEntry second;
  private JarEntry firstXml;

  @Before
  public void setUp() throws Exception {
    jarFileUser = new JarFileUser();

    // Create a mock for the JarFile parameter
    mockJarFile = createMock(JarFile.class);

    // User Vector to provide an Enumeration of JarEntry-Instances 
    Vector<JarEntry> entries = new Vector<JarEntry>();
    first = createMock(JarEntry.class);
    second = createMock(JarEntry.class);

    entries.add(first);
    entries.add(second);

    expect(first.getName()).andReturn("mocktest.JarFileUser.class");
    expect(second.getName()).andReturn("mocktest.Ignore$Me.class");

    mockJarEntries = entries.elements();

    expect(mockJarFile.entries()).andReturn(mockJarEntries);

    // JarEntry for the XML file
    firstXml = createMock(JarEntry.class);

    expect(mockJarFile.getJarEntry("TEST-mocktest.JarFileUser.xml")).andReturn(firstXml);

    // XML contents
    ByteArrayInputStream is = new ByteArrayInputStream("<test>This is a test.</test>".getBytes("UTF-8"));
    expect(mockJarFile.getInputStream(firstXml)).andReturn(is);

    replay(mockJarFile);
    replay(first);
    replay(second);
    replay(firstXml);
  }

  @Test
  public void testGetTestXml() throws IOException, ParserConfigurationException, SAXException {
    Map<String, Document> map = jarFileUser.getTestXml(mockJarFile);
    verify(mockJarFile);
    verify(first);
    verify(second);
    verify(firstXml);

    assertEquals(1, map.size());
    Document doc = map.get("mocktest.JarFileUser");
    assertNotNull(doc);
    final Element root = (Element) doc.getDocumentElement();
    assertNotNull(root);
    assertEquals("test", root.getNodeName());
    assertEquals("This is a test.", root.getTextContent());
  }

}

Note on additional libraries
JarFile is a class and not an interface so according to the EasyMock installation docs you should have Objenesis and cglib in your classpath.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文