您将如何测试静态方法URLEncoder.encode?

时间:2019-05-08 23:19:24

标签: java unit-testing junit

我有以下这种方法。

 protected static String encode(String url) {
    try {
      url = URLEncoder.encode(url, StandardCharsets.UTF_8.toString());
    } catch (Exception e) {
      LOGGER.warn("exception occured while encoding url {}", url);
    }
    return url;
  }

我无法为此提供junit测试,因为我无法模拟URLEncoder。这种方法可能有2种结果

  • 编码网址
  • 原始网址(如果有例外)

我能够为第一个结果创建测试方法。您将如何为第二个结果创建测试方法?

3 个答案:

答案 0 :(得分:1)

您可以使用PowerMockito模拟静态方法。假设您帖子中的静态方法在名为HelloWorld的类中,则这是两个测试,其中第一个测试测试的是肯定案例,第二个测试  正在测试例外情况:

import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.powermock.api.mockito.PowerMockito.doThrow;
import static org.powermock.api.mockito.PowerMockito.mockStatic;
import static org.powermock.api.mockito.PowerMockito.when;

@RunWith(PowerMockRunner.class)
@PrepareForTest(HelloWorld.class)
public class HelloWorldTest {

    @Test
    public void encode_returnsEncoded() throws UnsupportedEncodingException {
        // given
        mockStatic(URLEncoder.class);
        when(URLEncoder.encode(any(String.class), any(String.class)))
            .thenReturn("testUrlEncoded");

        // when
        String encoded = HelloWorld.encode("testUrl");

        // then
        assertThat(encoded).isEqualTo("testUrlEncoded");
    }

    @Test
    public void encode_returnsInputOnException() {
        // given
        mockStatic(URLEncoder.class);
        doThrow(new Exception("exception from test"))
            .when(URLEncoder.class);

        // when
        String encoded = HelloWorld.encode("testUrl");

        // then
        assertThat(encoded).isEqualTo("testUrl");
    }

}

答案 1 :(得分:1)

  

软件工程的基本定理(FTSE)是由安德鲁·科尼格(Andrew Koenig)提出的,用于描述巴特勒·兰普森(Butler Lampson)对已故戴维·J·惠勒(David J. Wheeler)的评价:      

    

“我们可以通过引入额外的间接级别来解决任何问题。”

  
     

[...]

     

该定理通常由幽默的子句“ ...,除了太多的间接级别的问题外,”,它指的是太多的抽象可能会产生其自身固有的复杂性问题。 (来源:Wikipedia

因此,假设有一个类具有名为encode的静态方法:

public final class UrlHelper {
    protected static String encode(String url) {
        try {
            url = URLEncoder.encode(url, StandardCharsets.UTF_8.toString());
        } catch (Exception e) {
            LOGGER.warn("exception occured while encoding url {}", url);
        }

        return url;
    }
}

并且您的代码取决于它:

public class MyClass {
    public void doSomething(String someUrl) {
        // ...
        String encodedUrl = UrlHelper.encode(someUrl);
        // ...
    }
}

,您想测试MyClass.doSomething(String someUrl),但想模拟UrlHelper.encode(someUrl)。一种选择是定义另一个类,例如

public final class MyUrlHelper {
    protected String encode(String url) {
        return UrlHelper.encode(someUrl); 
    }
}

由于MyUrlHelper.encode(String url)不是静态的,因此您可以重构原始代码并通过依赖注入和模拟非静态的MyUrlHelper.encode(String url)来对其进行测试:

// Refactored
public class MyClass {

    private MyUrlHelper myUrlHelper;

    public UrlHelper(MyUrlHelper muUrlHelper) {
        this.myUrlHelper = myUrlHelper;
    }


    public void doSomething(String someUrl) {
        // ...
        String encodedUrl = myUrlHelper.encode(someUrl);
        // ...
    }
}

// Test
@Test
public void myTest() {
    // setup myUrlHelper and configure it
    MyUrlHelper myUrlHelper = mock(MyUrlHelper.class);
    when(myUrlHelper.encode(...)).thenReturn(...);


    // inject
    MyClass myObject = new MyClass(myUrlHelper);

    // stimulate
    myObject.doSomething("...")
}

另一种选择是使用PowerMockRunner使用Mockito,如 @Marimuthu Madasamy 所述。


但是,在这里模拟UrlHelper.encodeURLEncoder.encode并没有任何好处。它不是外部系统(数据库,文件系统,消息代理,SOAP API,REST API等),因此我看不到通过模拟获得任何好处。

答案 2 :(得分:0)

如果您愿意使用Lombok,那么我为您提供了一种实用的方法:

int
  • Jacoco将忽略此方法
  • 不能在此处引发UnsupportedEncodingException。让龙目岛处理这种丑陋的情况。