Java 模拟时junit中出现错误

Java 模拟时junit中出现错误,java,unit-testing,junit,mocking,powermock,Java,Unit Testing,Junit,Mocking,Powermock,我是Junit新手,下面是我正在运行的Junit代码 package com.de.base.util.general; import static org.junit.Assert.*; import static org.mockito.Mockito.when; import java.util.HashMap; import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; import o

我是Junit新手,下面是我正在运行的Junit代码

package com.de.base.util.general;
import static org.junit.Assert.*;
import static org.mockito.Mockito.when;
import java.util.HashMap;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import org.powermock.api.mockito.PowerMockito;

@RunWith(MockitoJUnitRunner.class)
public class JReportUtilTest {
@InjectMocks 
ReportUtil w_res = new ReportUtil();

@Mock
CollectionUtil w_util;

@Test
public void test_removeHashedSettings() throws Exception {
    HashMap<String ,String> w_abc = new HashMap<String,String>();
    w_abc.put("abc","89");
    //CollectionUtil mock = org.mockito.Mockito.mock(CollectionUtil.class);
    //PowerMockito.mockStatic(CollectionUtil.class,w_abc);          
    when(w_util.createHashMap("abc:89", ":")).thenReturn(w_abc);
    assertEquals("abc:89:",ReportUtil.removeHashedSettings("1", "abc:89", ":"));
}
}
下面是CollectionUtil中createHashMap的代码,我必须对其进行模拟

public static HashMap<String, String> createHashMap(String a_NameValStr, String a_Delim)// throws Exception
    {
        HashMap<String, String> w_KeyVal = new HashMap<String, String>();
        if (LOGGER.isInfoEnabled()) LOGGER.info("CollectionUtil:createHashMap:Hashing string: "+ a_NameValStr );

        if(a_NameValStr == null) return w_KeyVal;

            StringTokenizer w_StrTkn = new StringTokenizer(a_NameValStr, a_Delim);
            if( w_StrTkn.countTokens() == 0 || (w_StrTkn.countTokens()%2) != 0 )
            {
                LOGGER.warn("CollectionUtil:createHashMap:Invalid number of tokens to hash: "+ a_NameValStr+":"+w_StrTkn.countTokens() );
                return w_KeyVal;
            }

            while (w_StrTkn.hasMoreTokens()) w_KeyVal.put( w_StrTkn.nextToken(), w_StrTkn.nextToken());
        System.out.println(w_KeyVal);   
        return w_KeyVal;
    }
我正在使用mockito-all-1.10.19.jar、powermock-api-mockito-1.6.6.jar、powermock-core-1.6.6.jar、powermock-module-junit4-1.6.6.jar
有人能帮我解决这个问题吗?

您不使用PowerMock runner:

@RunWith(PowerMockRunner.class)
Mockito无法模拟静态方法,但PowerMock可以

您应该使用静态方法模拟该类:

PowerMockito.mockStatic(CollectionUtil.class);
无论如何,更好的设计是用实例方法取代静态方法。
静态方法不是自然可测试的,并且强制创建复杂且不可读的解决方法。
例如,查看测试简单类所需的依赖项组合的复杂性。

您应该保持使用静态方法作为助手,这些方法不执行域的核心逻辑,也不需要模拟 当这些方法执行域的核心逻辑时,就像
createHashMap()静态方法
的情况一样,您很可能需要对其进行模拟,以避免在测试期间在依赖类之间产生副作用
正如您所注意到的:模拟静态方法非常笨拙,因为静态方法实际上不是设计为被重写的。

此外,对于域的核心逻辑,您应该能够利用OOP(继承性、多态性、设计模式等),如何用静态方法实现它


对于遗留代码,我们不能真的不更改,这是可以接受的,但除此之外,不可以,您应该重构代码。

以下是我的工作代码:

import static org.junit.Assert.assertEquals;

import java.util.HashMap;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mockito;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;

@RunWith(PowerMockRunner.class)
@PrepareForTest(CollectionUtil.class)
public class TestHarnesTest {
    @InjectMocks
    TestHarnes w_res = new TestHarnes();

    @Before
    public void before() {
        PowerMockito.mockStatic(CollectionUtil.class);
    }

    @Test
    public void test_removeHashedSettings() throws Exception {
        HashMap<String, String> w_abc = new HashMap<String, String>();
        w_abc.put("abc", "89");
        // CollectionUtil mock = org.mockito.Mockito.mock(CollectionUtil.class);
        // PowerMockito.mockStatic(CollectionUtil.class,w_abc);
        PowerMockito.when(CollectionUtil.createHashMap(Mockito.eq("abc:89"), Mockito.eq(":"))).thenReturn(w_abc);
        assertEquals("abc:89:", TestHarnes.removeHashedSettings("1", "abc:89", ":"));
    }
}

CollectionUtil是最终类吗?它不是最终类您试图在
CollectionUtil
中模拟的方法是静态的,因此您需要在类上使用
@RunWith(PowerMockRunner.class)
@PrepareForTest(CollectionUtil.class)
。此外,您还需要调用
PowerMockito.mockStatic(CollectionUtil.class)如上所述,我正在使用3个powermock JAR。但在实现您的代码时,我仍然会遇到此错误。无法解析类型org.powermock.api.support.membermodification.MemberModifier。它是从必需的类文件中间接引用的。如果缺少依赖项,或者IDE未刷新。当我说我强制创建复杂的解决方法时:看看测试简单类所需的混合依赖的复杂性。对于没有状态的实用程序类,为什么使用静态方法不是一个好的设计?它保存了对象的创建,从而产生了更短、更干净的生产代码。@Yoav Gur我同意静态方法是一个助手,它不执行域的核心逻辑,因此您不需要模拟它。当它像这里一样执行域的核心逻辑时,您可能需要模拟它,以避免在测试期间在依赖类之间产生副作用。而您模拟的静态方法不是更短的更干净的代码。此外,对于域的核心逻辑,您应该能够利用OOP(继承性、多态性、设计模式等),如何用静态方法实现它?我在PowerMockito.mockStatic(CollectionUtil.class)中遇到了错误;错误为:-无法解析类型org.powermock.api.support.membermodification.MemberModifier。它是从required.class文件间接引用的。您的CollectionUtil类是什么?它来自哪个框架?感谢您的帮助。但是当我运行您的代码时,生成了以下错误。java.lang.NoClassDefFoundError:org/powermock/api/mockito/expectation/With或WithioutExpectedArguments
PowerMockito.mockStatic(CollectionUtil.class);
import static org.junit.Assert.assertEquals;

import java.util.HashMap;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mockito;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;

@RunWith(PowerMockRunner.class)
@PrepareForTest(CollectionUtil.class)
public class TestHarnesTest {
    @InjectMocks
    TestHarnes w_res = new TestHarnes();

    @Before
    public void before() {
        PowerMockito.mockStatic(CollectionUtil.class);
    }

    @Test
    public void test_removeHashedSettings() throws Exception {
        HashMap<String, String> w_abc = new HashMap<String, String>();
        w_abc.put("abc", "89");
        // CollectionUtil mock = org.mockito.Mockito.mock(CollectionUtil.class);
        // PowerMockito.mockStatic(CollectionUtil.class,w_abc);
        PowerMockito.when(CollectionUtil.createHashMap(Mockito.eq("abc:89"), Mockito.eq(":"))).thenReturn(w_abc);
        assertEquals("abc:89:", TestHarnes.removeHashedSettings("1", "abc:89", ":"));
    }
}
public class TestHarnes {

    public static String removeHashedSettings(final String key, final String a_settings, final String deilimiter) throws Exception {
        if (!(key != null && key.trim().length() > 0)) {
            return a_settings;
        }
        if (!(a_settings != null && a_settings.trim().length() > 0)) {
            return a_settings;
        }

        HashMap hSettings = CollectionUtil.createHashMap(a_settings, deilimiter);
        hSettings.remove(key);
        return getSettingFromHash(hSettings, deilimiter);
    }

    private static String getSettingFromHash(final HashMap hSettings, final String deilimiter) {
        return "";
    }

}