【问题标题】:Junit Interface PowermockJunit 接口 Powermock
【发布时间】:2013-05-07 13:58:12
【问题描述】:

编辑: 用更短的方式重写了这个问题。感谢您指出了这一点! :)

我需要编写 JUnit 测试,我必须在没有 setter/getter 的情况下模拟几个私有方法和字段。我尝试了两种方法来完成它,使用 Mockito 和 PowerMock。问题是,这两者可以结合吗? 首次尝试使用私有字段测试方法:

...
@Mock private XMLConfiguration config;
@InjectMocks AAIGroupController groupi;

@Before
public void setUp() {
    MockitoAnnotations.initMocks(this);
}
...

    given(config.configurationsAt(anyString())).willReturn(ldapGroups);
...

第二次尝试使用 PowerMock 测试私有方法:

...
AAIGroupController groupC = PowerMockito.spy(new AAIGroupController());
...
when(groupC, method(AAIGroupController.class, "getLdapGroupNodeFromGroupConfigFile", ELUser.class))
        .withArguments(any(ELUser.class))
        .thenReturn(sn);
assertTrue(iaigroupi.isPosixAccount(new ELUserAAI(null, true, false)));
...

有没有办法将它们结合起来,还是我应该只使用 PowerMock?我无法使用 PowerMock 模拟私有字段。

另一个问题是:我必须为接口编写 JUnit 测试。这是废话吗,因为实现接口的类已经过测试。如果没有,什么是好的做法?

提前致谢!

老问题,完全可以跳过。我只是把它放在这里是为了理解已经给出的答案。

我必须为已经完成实现的接口编写 JUnit 测试。但是我有点困惑如何正确地为他们编写测试。我已经开始实施,但我现在卡住了。首先,我不确定我是否正确测试了接口,然后模拟私有字段存在问题。 到目前为止,我已经编写了两个不同的测试类来尝试一些事情。 两个测试类现在都在“工作”,但我想将它们合并到 InterfaceAAIGroupControllerTest 类中,但不知道如何在 PowerMock 中使用 Mockito。 对于界面,我使用

groupi = PowerMockito.spy(new AAIGroupController());

对于我使用的其他测试

@Mock private XMLConfiguration config;
@InjectMocks AAIGroupController groupi;

@Before
public void setUp() {
    MockitoAnnotations.initMocks(this);
}

代码:

界面:

public interface IAAIGroupController {

/**
* Appends a new group entry
*/
public void appendGroup();

/**
 * checks if a given account is a possix account
 * 
 * @param elUser the user object to check
 * @return true if is posix, otherwise false
 * @throws ConfigurationException
 */
public boolean isPosixAccount(ELUser elUser)

...

实现

@Override
public void appendGroup() {
    try {
        config.addProperty("ldapGroup(-1)",

        List<SubnodeConfiguration> ldapGroups = config.configurationsAt("ldapGroup");
        SubnodeConfiguration sn = ldapGroups.get(ldapGroups.size()-1);
        try {
            sn.addProperty("script(-1)", null);
            // TODO Configuration 
        } catch (Exception e) {
            sn.addProperty("script(-1)", "default.sh");
        }

        config.save();
    } catch (ConfigurationException ex) {
        LOGGER.log(Level.SEVERE, ex.getMessage());
    }
}

@Override
public boolean isPosixAccount(final ELUser elUser) throws ConfigurationException {
    SubnodeConfiguration ldapGroup = getLdapGroupNodeFromGroupConfigFile(elUser);
    String posix = ldapGroup.getString("[@posix]");
    if (posix == null || posix.isEmpty() || posix.equalsIgnoreCase("true")) {
        return true;
    } else if (posix.equalsIgnoreCase("false")) {
        return false;
    } else {
        throw new ConfigurationException("posix attribute is not set properly!");
    }
}

接口测试代码,暂时不能很好地处理异常,当它工作时会修复它。 我正在使用 PowerMock,因为我必须在实现中调用私有方法。 不知道这样能不能很好的测试Interfaces。

@RunWith(PowerMockRunner.class)
@PrepareForTest(AAIGroupController.class)
public class InterfaceAAIGroupControllerTest {

    public IAAIGroupController iaigroupi;
    public AAIGroupController groupi;
    public XMLConfiguration config;


    @Before
    public void setUp() {
        groupi = PowerMockito.spy(new AAIGroupController());
        config = Whitebox.getInternalState(groupi, "config");
        iaigroupi = groupi;
    }

    @Test
    public void isPosixAccount_True() {
        try {
        SubnodeConfiguration sn = mock(SubnodeConfiguration.class);
        when(iaigroupi, method(AAIGroupController.class, "getLdapGroupNodeFromGroupConfigFile", ELUser.class))
        .withArguments(any(ELUser.class))
        .thenReturn(sn);

            assertTrue(iaigroupi.isPosixAccount(new ELUserAAI(null, true, false)));
        } catch (ConfigurationException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

实现的测试代码,这里我使用 Mockito 来模拟一个私有字段 在代码中使用,但从未由构造函数或方法设置。

@RunWith(MockitoJUnitRunner.class)
public class AAIGroupControllerTest {

    @Mock private XMLConfiguration config;
    @InjectMocks AAIGroupController groupi;

    @Before
    public void setUp() {
        MockitoAnnotations.initMocks(this);
    }

    @Test
    public void appendGroupTest() {
        List<SubnodeConfiguration> ldapGroups = mock(List.class);
        SubnodeConfiguration sn = mock(SubnodeConfiguration.class);
        given(config.configurationsAt(anyString())).willReturn(ldapGroups);
        given(ldapGroups.size()).willReturn(11);
        given(ldapGroups.get(ldapGroups.size()-1)).willReturn(sn);
        groupi.appendGroup();
        verify(sn).addProperty("script(-1)", null);
    }

}

我现在的问题是,我可以像以前那样测试接口吗? tbh 似乎不是一个很好的解决方案。参数化似乎没有必要,因为总是只有一个实现,我不知道如何使用两个 Runners.. 另一件事是,我如何使用上一个示例中的测试代码,我在 PowerMock 测试类中模拟私有字段“config”?我不知道如何正确模拟私有字段并在从中调用方法时更改其行为。

提前感谢您的每一个提示!

【问题讨论】:

    标签: junit mockito powermock


    【解决方案1】:

    阅读本文时,我想到了三个想法:

    • 您真的需要发布那么多代码吗?您真的希望我们阅读全部内容吗?你的问题很模糊,很难理解。考虑一次只问一个问题。
    • 您不测试接口。一个接口没有任何代码,有什么可测试的?
    • 如果您使用PowerMock 进行模拟,请不要在同一测试中同时使用Mockito。根据您的要求使用其中一种或另一种

    要设置私有字段,可以提供一个 setter(可能在默认范围内)或使用反射(例如 ReflectionTestUtils)来设置它。

    【讨论】:

    • 你只需要考虑这里的海报没有报酬,主要是为了好玩。如果我们必须清理大量代码并且问题不简洁,那么大多数人都会转向另一个问题。如果您的问题易于阅读,您将获得最多的回复。
    • 感谢您的回答。这是我第一次来,不知道要发多少,所以我认为信息太多总比不够好,好吧.. :S 这是测试接口的要求,我认为公共API通过它的接口表达, 是一个重要的测试点。很高兴知道,所以我将通过测试将它们分开。下一次,如果有的话,我会尽量压缩我的问题,只发布重点。再次感谢有用的提示。 :)
    • 无论谁提出了这个要求,都需要学习软件工程课程,或者对接口和抽象类感到困惑。如果您尝试测试一个接口,那么您所测试的只是模拟框架。一种有效的选择是针对 API / 接口设计测试,然后将一个或多个具体实现传递给它以进行测试,以验证它们是否实现了正确的接口。如果同一个接口有多个实现,这种设计可以允许测试重用。
    • 我将只对实现进行 JUnit 测试。哪一种很有意义.. 针对 API 的测试发生在集成测试期间,因此应该涵盖这一点。感谢您花时间回答新手。 :)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-01-17
    • 1970-01-01
    • 2015-12-12
    相关资源
    最近更新 更多