如何编写Junit for Interface默认方法

qltillow  于 12个月前  发布在  其他
关注(0)|答案(5)|浏览(163)

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

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

字符串
ABC:接口名称
DEFXYZ:类名

iyzzxitl

iyzzxitl1#

如果你使用的是Mockito,单元测试默认(也称为“防御者”)方法的最简单方法是使用接口类literal2创建一个spy1。然后可以在返回的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));
    }
}

字符串
(使用Java 8和mockito-2.24.5测试)
1人们经常警告说,使用spy可能意味着代码或测试气味,但测试默认方法是一个完美的例子,说明使用spy是一个好主意。
2截至撰写本文时(2019年),接受类字面量的spy的签名标记为@Incubating,但自2014年发布的mockito-1.10.12以来一直存在。此外,自2016年发布的mockito-2.1.0以来,support for default methods in Mockito一直存在。似乎可以肯定的是,这种方法将在未来的Mockito版本中继续工作。

nwwlzxa7

nwwlzxa72#

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

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;
    }
}

字符串
为同一个方法创建了一个实现类,可选地,你可以创建另一个方法来调用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;
    }
}


实现的相应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"));
    }
}

3hvapo4f

3hvapo4f3#

我认为有一个更简单的方法。它包括在测试类中使用要测试的方法实现接口,并直接调用默认类型的方法。如果需要,内部调用的对象会被模拟。前面的例子是这样的:
接口)

public interface ABC<T, D, K, V> {
    default List<String> getSrc(DEF def, XYZ xyz) throws Exception {
      list<String>() result=new Arraylist<String>();
      result.add(def.toString());
      result.add(xyz.toString());
      return result;
    }
}

字符串
测试类)

...        
@RunWith(MockitoJUnitRunner.class)
public class ABCTest implements ABC{

    @Test
    public void testGetSrc() {

        list<String>() result=getSrc(new DEF("Hi!"),new XYZ("bye!"));

        int actual=result.size();
        int expected=2;
        assertEquals(expected, actual);

    }


如果你需要测试一个异常的启动,从错误的参数中强制释放并正确配置测试就足够了:

...        
@Test(expected = GenericRuntimeException.class)
public void test....
...


我已经用类似的代码检查过了,它工作正常。它也在覆盖率分析中正确收集。

mwngjboj

mwngjboj4#

答案很简单,不需要mocking或spying,只需要为接口创建一个匿名对象,而不需要覆盖默认方法。
例如:

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));
  }
}

字符串

rlcwz9us

rlcwz9us5#

你可以创建一个类来实现你的接口,或者让你的测试实现它。第二个似乎是一个更短的解决方案:

public class FunctionCallingTransactionTemplateTest implements FunctionCallingTransactionTemplate {
    private final Object object = Mockito.mock(Object.class);

    @Test
    public void should_invoke_function() throws Exception {
        // given
        when(object.toString()).thenReturn("salami");

        // when
        String result = functionCallingTransactionTemplate().execute((status) -> object.toString());

        // then
        assertThat(result).isEqualTo("salami");
    }
}

字符串

相关问题