测试静态方法,该方法需要模拟成员方法并使用PowerMockito抑制单例构造函数

问题描述 投票:0回答:1

我想测试一个静态方法(例如HobbyUtil.java:shareReadContext(int lineNumber)),该方法将要求Singleton类(例如Shelf.java)获取对象(例如Book)以进一步获取值(例如上下文)返回的对象。

但是,在模拟案例执行期间,该Singleton类(即Shelf.java)的ctor将触发链中的其他几个Singleton类(例如LibraryA.java);并且其中之一会触发java.lang.ExceptionInInitializerError

我认为嘲笑/监视那些不相关的Singleton类超出了Mock Test的精神,因为它们与我的测试范围无关。

因此,我决定取消此Singleton类(即Shelf.java)的私有ctor,只让该类中的getter方法(即getBook())返回具有我喜欢的行为的模拟对象,该对象将与我的行为完全匹配测试用例。

我遇到的问题是,我通过以下链接成功抑制了[[Shelf.java的ctor:suppress a singleton constructor in java with powermock

但是我无法弄清楚让此getter方法返回我想要的东西(即返回一个模拟对象)的方法。

我正在使用的

PowerMockito,hamcrestJUnit的版本在此处列出以供参考:

<dependency><groupId>org.powermock</groupId><artifactId>powermock-module-junit4</artifactId><version>1.7.0</version><scope>test</scope></dependency> <dependency><groupId>org.powermock</groupId><artifactId>powermock-api-mockit02</artifactId><version>1.7.0</version><scope>test</scope></dependency> <dependency><groupId>org.hamcrest</groupId><artifactId>hamcrest-all</artifactId><version>1.3</version><scope>test</scope></dependency> <dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version><scope>test</scope></dependency>
[我还用下面的示例类复制了案例,以显示遇到的问题(HobbyUtilTest.java是我的测试案例的类:]

假设应用程序中有5个Java类:

public interface Book { public String getContext(int lineNumber); }

public class Shelf {

    private static final Shelf shelf = new Shelf();
    private String BOOK_NAME = "HarryPotter";
    private Book book = null;

    private Shelf() {
        book = LibraryA.getInstance().getBook(BOOK_NAME);
        // many relatively complicated logics are here in actual class ... 
        // I want to suppress this ctor 
    }

    public static Shelf getInstance() {
        return shelf;
    }

    public Book getBook() {
        return book;  // I want to return my mocked object while calling this method in test case
    }

}
public class HobbyUtil {

    public static String shareReadContext(int lineNumber){
        String context = "";
        Book book = Shelf.getInstance().getBook();

        for (int i = 0 ; i < lineNumber; i++) {
            context += book.getContext(i);
        }
        return context;
    }

    private HobbyUtil() {}
}
public class LibraryA {
    private static final LibraryA library = new LibraryA();
    private Book book;

    private LibraryA() {
        throw new java.lang.ExceptionInInitializerError();
    }

    public static LibraryA getInstance() {
        return library;
    }

    public Book getBook(String bookName) {
        return book;
    }
}
public class BookImpl implements Book{

    private String bookName = null;

    BookImpl(String bookName){
        this.bookName = bookName;
    }

    @Override
    public String getContext(int lineNumber) {
        return lineNumber + ": Context";
    }
}
并且我会用shareReadContext(int lineNumber)测试HobbyUtil.java中的静态方法HobbyUtilTest.java

import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.MatcherAssert.assertThat; import static org.mockito.ArgumentMatchers.anyInt; import static org.powermock.api.mockito.PowerMockito.when; import org.junit.Test; import org.junit.runner.RunWith; import org.powermock.api.mockito.PowerMockito; import org.powermock.core.classloader.annotations.PrepareForTest; import org.powermock.modules.junit4.PowerMockRunner; @RunWith(PowerMockRunner.class) @PrepareForTest(value = { Shelf.class }) public class HobbyUtilTest { @Test public void testShareReadContext() throws Exception { Book mockBook = PowerMockito.mock(Book.class); when(mockBook.getContext(anyInt())).thenReturn("context for test"); PowerMockito.suppress(PowerMockito.constructor(Shelf.class)); //PowerMockito.spy(Shelf.class); //when(Shelf.getInstance().getBook()).thenReturn(mockBook); // does not work //PowerMockito.doReturn(mockBook).when(Shelf.getInstance().getBook()); // does not work //PowerMockito.when(Shelf.class, "getBook").thenReturn(mockBook); // does not work //TODO any approach for it? String context = HobbyUtil.shareReadContext(1); assertThat(context, is("context for test")); } }

[任何人都可以帮助建议我如何让Book book = Shelf.getInstance().getBook();中的HobbyUtil.java行返回我的模拟对象(即mockBook)?
java unit-testing mocking mockito powermockito
1个回答
0
投票
假设您的Shelf类位于程序包test中,这应该有效:
© www.soinside.com 2019 - 2024. All rights reserved.