模拟私有构造函数

Mocking a private constructor

Site class 是由外部团队提供给我的,并且有一个 private 构造函数。

public class Site
{
   int id;
   String brand;

   private Site(int id, String brand)
   {
      this.id = id;
      this.brand = brand;
   }
}

SiteUtil class(由团队控制)是

public class SiteUtil
{
   public static Site getSite()
   {
     Site site;
     //Logic
     return site; 
   }
 }

getSite() 函数应用其逻辑的数据需要网络调用,因此需要对其进行模拟。目前没有setter(可能是为了和数据源保持一致,不太确定)

我模拟如下

Site mockSite = new Site(1,"Google");
PowerMockito.when(SiteUtil.getSite(1)).thenReturn(mockSite);

上面的代码当然不会编译,因为我使用 public 构造函数。 我读到的解决方案是模拟 Site 对象的私有构造函数。然而,我不知道该怎么做(第一次编写单元测试!)

假设您的代码仅通过 getter 访问 idbrand 的值,您可以简单地模拟 class Site 然后 return当您调用静态方法 SiteUtil.getSite() 作为下一个时,此模拟:

// Use the launcher of powermock
@RunWith(PowerMockRunner.class)
public class MyTestClass {

    @Test
    // Prepare the class for which we want to mock a static method
    @PrepareForTest(SiteUtil.class)
    public void myTest() throws Exception{
        // Build the mock of Site
        Site mockSite = PowerMockito.mock(Site.class);
        // Define the return values of the getters of our mock
        PowerMockito.when(mockSite.getId()).thenReturn(1);
        PowerMockito.when(mockSite.getBrand()).thenReturn("Google");
        // We use spy as we only want to mock one specific method otherwise
        // to mock all static methods use mockStatic instead
        PowerMockito.spy(SiteUtil.class);
        // Define the return value of our static method
        PowerMockito.when(SiteUtil.getSite()).thenReturn(mockSite);

        ...
    }
}

作为替代方法,如果您可以获得管理层的支持,则有一种方法可以兼容地改变他们的 API。不要将网络查找隐藏在 getSite() 方法中,而是将它们外部化为 SiteLookupStrategy:

public class SiteUtil {
    private static SiteLookupStrategy strategy = new DefaultSiteLookupStrategy();

    public static Site getSite(int siteNum) {
        return strategy.lookup(siteNum);
    }

    public static void setLookupStrategy(SiteLookupStrategy strategy) {
        SiteUtil.strategy = strategy;
    }
}

这样,为了进行测试,您可以注入自己的(模拟的)策略,但不需要更改代码的现有客户端。 (这还有一个好处,就是让查找本身更容易针对该组进行测试。)