如何编写Junit for Interface默认方法

Jec*_*ech 8 java junit unit-testing java-8

请帮助编写Junit接口默认方法.

public interface ABC<T, D, K, V> {
    default List<String> getSrc(DEF def, XYZ xyz) throws Exception {
    }
}
Run Code Online (Sandbox Code Playgroud)

ABC:接口名称.DEF和XYZ:类名

hee*_*nee 16

如果您使用的Mockito,到单元测试默认的最简单的方法(又名“卫士”)的方法是做一个1使用接口类字面2。然后可以照常在返回的 spy 实例上调用默认方法。以下示例演示:spy

import org.junit.Test;

import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.spy;

interface OddInterface {
    // does not need any unit tests because there is no default implementation
    boolean doSomethingOdd(int i);

    // this should have unit tests because it has a default implementation
    default boolean isOdd(int i) {
        return i % 2 == 1;
    }
}

public class OddInterfaceTest {
    OddInterface cut = spy(OddInterface.class);

    @Test
    public void two_IS_NOT_odd() {
        assertFalse(cut.isOdd(2));
    }

    @Test
    public void three_IS_odd() {
        assertTrue(cut.isOdd(3));
    }
}
Run Code Online (Sandbox Code Playgroud)

(使用 Java 8 和mockito-2.24.5 测试

1人们经常警告说,使用 aspy可以表示代码或测试气味,但测试默认方法是使用 aspy是个主意的完美示例。

2截至撰写本文时(2019 年),spy其接受类文字的签名标记为@Incubating,但自2014 年发布的mockito-1.10.12以来一直存在。此外,Mockito中的默认方法支持自2016 年发布的mockito-2.1.0以来。似乎可以肯定的是,这种方法将在 Mockito 的未来版本中继续有效。


Sri*_*m M 6

答案非常简单。不需要模拟或监视,只需为接口创建一个匿名对象,而不覆盖默认方法。

前任:

interface Adder {
  default sum(Integer...n) {
    return Arrays.stream(n).reduce(0, Integer::sum);
  }
} 

// Junit 4
class AdderTest {

  private Adder adder;

  @Before
  public void setup() {}
    adder = new Adder(){}; // not overriding default methods
  }

  @Test
  public void testSum() {
    Assert.assertEquals(3, adder.sum(1, 2));
  }
}
Run Code Online (Sandbox Code Playgroud)


Arp*_*wal 5

正如答案中所建议的,为接口创建实现类并对其进行测试,例如我getSrc在您的ABC接口中修改了方法,如下所示:

import java.util.ArrayList;
import java.util.List;

public interface ABC<T, D, K, V> {

    default List<String> getSrc(DEF def, XYZ xyz) {
        final List<String> defaultList = new ArrayList<>();
        defaultList.add("default");
        defaultList.add("another-default");
        return defaultList;
    }
}
Run Code Online (Sandbox Code Playgroud)

为其创建了一个实现类,您可以选择创建另一个调用 super 方法的方法并@Test为两者编写,就像我一样:

import java.util.List;

public class ABCImpl implements ABC<String, Integer, String, Integer> {

    public List<String> getSrcImpl(DEF def, XYZ xyz) {
        final List<String> list = getSrc(def, xyz);
        list.add("implementation");
        return list;
    }
}
Run Code Online (Sandbox Code Playgroud)

实现对应的Test类如下:

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.empty;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.contains;
import java.util.Collection;
import java.util.List;

import org.junit.Before;
import org.junit.Test;

public class ABCImplTest {

    private ABCImpl abcImpl;

    @Before
    public void setup() {
        abcImpl = new ABCImpl();
    }

    @Test
    public void testGetSrc() throws Exception {
        List<String> result = abcImpl.getSrc(new DEF(), new XYZ());
        assertThat((Collection<String>) result, is(not(empty())));
        assertThat(result, contains("default", "another-default"));
    }


    @Test
    public void testABCImplGetSrc() throws Exception {
        List<String> result = abcImpl.getSrcImpl(new DEF(), new XYZ());
        assertThat((Collection<String>) result, is(not(empty())));
        assertThat(result, contains("default", "another-default", "implementation"));
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 我认为也许创建一个内部类或匿名类实现可能更好地测试默认方法,因为该实现将来可能会覆盖默认方法。 (2认同)