如何在单元测试期间访问 .war 类路径中的文件?

Posted

技术标签:

【中文标题】如何在单元测试期间访问 .war 类路径中的文件?【英文标题】:How to access a file in the .war classpath during unit tests? 【发布时间】:2013-03-28 03:56:52 【问题描述】:

我有一个 Web 应用程序项目,我正在尝试对使用 FreeMarker 模板创建文件的方法进行单元测试。我的方法 createFile() 应该采用 MyFile 类型 - 包含要创建的文件名和 FreeMarker 需要的 rootMap 以及模板名称 - 并使用我提供的模板创建文件。

我正在关注Freemarker manual 来设置模板加载器。问题是,我正在使用 TemplateLoader setClassForTemplateLoading(Class, String) 方法来查找模板路径。这个模板加载器使用 Class.getResource() 来获取类路径。

但是,由于我使用的是 Maven,我的 java 代码位于 /src/main/java,我的模板位于 /src/main/webapp/templates/,我的测试代码位于 /src/test/java。因此,我的 Class.getResource("/")(根类路径)总是返回 <PATH_TO_PROJECT>/target/test-classes/

因为我要部署战争,所以我不能使用 setDirectoryForTemplateLoading(File)。另外,由于我正在测试我的应用程序,因此我没有可与 setServletContextForTemplateLoading(Object, String) 一起使用的 ServletContext。

如何从测试用例访问我的模板文件夹?

这是我的测试代码的简化示例(我使用 mockito 来模拟 MyFile 类的行为):

private MyFile myFile;
private FileGenerator fileGenerator;

@Before
public void setUp() 
    myFile = new MyFile(...);
    fileGenerator = new FileGenerator(myFile, ...);


@Test
public void shouldCreateFile() 
    final MyFile mockedMyFile = spy(file);
    final Map<String, Object> rootMap = new HashMap<String, Object>();

    // populates rootMap with stuff needed for the Template

    // mocking method return
    when(mockedMyFile.getRootMap()).thenReturn(rootMap);

    // replacing the MyFile implementation with my Mock
    fileGenerator.setMyFile(mockedMyFile);

    // calling the method I want to test
    fileGenerator.createFile();

    assertTrue(MyFile.getFile().exists());

这是我正在测试的代码的简化:

public void createFile() 
    final Configuration cfg = new Configuration();
    cfg.setClassForTemplateLoading(getClass(), "templates/");
    try 
        myFile.getFile().createNewFile();
        final Template template = cfg.getTemplate("template.ftl");
        final Writer writer = new FileWriter(myFile.getFile());
        template.process(myFile.getRootMap(), writer);
        writer.flush();
        writer.close();
    
    // exception handling

【问题讨论】:

既然你已经在使用mockito,你可以试试powermock来模拟Class.getResource()等静态/最终/私有方法 真正使用 /src/main/test 作为测试代码而不是 src/test/java ? @Grove 我会试试的!谢谢 @khmarbaise 哎呀你是对的,解决了我的问题 你可以修改你的类以更容易测试。 Freemarker Configuration 对象通常用作单例——不是为每次调用构建的。如果Configuration 被注入到类中,那么您可以模拟它或在测试中使用替代模板加载器。 【参考方案1】:

我采纳了 Charles Forsythe 的建议,效果很好。

我刚刚向 FileGenerator 类添加了一个 templateLoader 成员,它有自己的 getter 和 setter。

接下来,在我的 createFile 方法中,我使用 Configuration 类中的方法 setTemplateLoader(TemplateLoader),如下所示:

public void createFile() 
    final Configuration cfg = new Configuration();
    // Changed
    cfg.setTemplateLoader(templateLoader);
    // the rest

最后,我只是为我的测试创建了一个模板加载器:

@Test
public void shouldCreateFile() 
    final MyFile mockedMyFile = spy(file);
    final Map<String, Object> rootMap = new HashMap<String, Object>();
    TemplateLoader templateLoader = null;

    try 
        templateLoader = new FileTemplateLoader(new File("<PATH TO TEMPLATE FOLDER>"));
     catch (final IOException e) 
        e.printStackTrace();
    

    gerador.setTemplateLoader(templateLoader);
    // the rest

问题解决了。在我的生产代码中,我使用 ClassTemplateLoader 而不是 FileTemplateLoader。

【讨论】:

以上是关于如何在单元测试期间访问 .war 类路径中的文件?的主要内容,如果未能解决你的问题,请参考以下文章

在单元测试期间获取引用项目的路径

在 Unity3d 的 Unity Test Runner 中的单元测试期间加载文件

idea 打包springboot项目报错:404

如何使用 eclipse-plugin 打包将 Mockito 添加到 Tycho 的单元测试中的测试类路径

如何在单元测试中访问 Dart 类

如何在单元测试期间注入 PersistenceContext?