首页 > 解决方案 > 如何使用mockito测试从静态值作为参数调用另一个void函数的函数

问题描述

我有一个 A 类

Class A{
 private static final String ANON_DIR             = "/webapps/worldlingo/data/anonymizer/";
 private static final String NO_ANON             = "noanonymize";

  public String first(String text, String srclang, Map dictTokens) {
      Set<String> noAnonymize = new HashSet<String>();
      second(noAnonymize,ANON_DIR + NO_ANON, "tmpLang","name");

      String value;
      if(noAnonymize.contains("test")){
      value = word;
      }
      else {
         value = "test";
        }

    return value;
}

其中 ANON_DIR 和 NO_ANON 是静态最终值。这个类有函数第一和函数第二。第一个函数中有一个调用方法,它调用第二个函数。第二个函数是 void 函数,它以静态字段为参数。

第二个函数只是文件读取函数,路径提供为

private void second (Set<String> hashSet, String path, String lang , String type) {
    FileReader fr = null;
    BufferedReader br = null;

    try {
      fr = new FileReader(path);
      br = new BufferedReader(fr);
      String Line;
      while ((Line = br.readLine()) != null) {
        hashSet.add(Line);
      }
    } catch (IOException e) {
      log.error("Anonymizer: Unable to load file.", e);

    } finally {
      try {
        if (fr != null) {
          fr.close();
        }
        if (br != null) {
          br.close();
        }
      } catch (IOException e) {
        log.error("Anonymizer : An error occured while closing a resource.", e);
      }
    }
  }

  } 

现在我正在尝试首先使用 mockito 测试该功能。我正在尝试更改静态参数并将这些更改的静态参数发送为

public void testfirst() throws Exception {
    A anon = new A();


    Field ANON_DIR = A.class.getDeclaredField("ANON_DIR");
    ANON_DIR.setAccessible(true);

    //java relection to change private static final field
    Field modifiersField = Field.class.getDeclaredField("modifiers");
    modifiersField.setAccessible(true);
    modifiersField.setInt(ANON_DIR, ANON_DIR.getModifiers() & ~Modifier.FINAL);
    ANON_DIR.set(null,"test");

    Field NO_ANON = A.class.getDeclaredField("NO_ANON");
    NO_ANON.setAccessible(true);

    Field modifiersField1 = Field.class.getDeclaredField("modifiers");
    modifiersField1.setAccessible(true);
    modifiersField1.setInt(NO_ANON, NO_ANON.getModifiers() & ~Modifier.FINAL);
    NO_ANON.set(null,"/noanonymize");


    Method anonymizeNames = anon.getClass().getDeclaredMethod("first", String.class, String.class , Map.class);
    String srcLang = "MSFT_EN";
    Map mapTokens = new HashMap();
    String result = (String) anonymizeNames.invoke(anon,"I am David",srcLang,mapTokens);


  }

问题:在这里,我可以使用 java 反射更改私有最终静态字段 ANON_DIR 和 NO_ANON,但更改后的字段不会发送到第二个函数。从第一个函数调用的第二个函数采用原始值而不是更改值。即当第二个被调用时,ANON_DIR 的值是“/webapps/worldlingo/data/anonymizer/”而不是“test”。

由于我将 ANON_DIR 的值更改为“test”,因此我希望将相同的“test”值传递给第二个函数。我怎样才能实现这一点来测试 void 第二种方法。

标签: javaunit-testingreflectionmockito

解决方案


这里的问题是违反了关注点分离原则。

的测试代码(剪切)太多,因此您很难找到接缝来替换依赖项。

对单元测试的目的也存在误解。您不测试代码,而是测试公共可观察行为,即任何返回值与依赖项的通信 (但不一定是公共方法)

所以我的建议是将方法移动second()到自己的新类中。cut 获得了这个作为构造函数参数传入的新类的实例。然后很容易在你的测试中用一个新类的模拟来替换真正的依赖。

另一方面,您可以通过使用PowerMock简单地屈服于您糟糕的设计......


推荐阅读