【问题标题】:How to write Junit for Interface default methods如何为接口默认方法编写 Junit
【发布时间】:2017-01-22 11:00:06
【问题描述】:

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

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

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

【问题讨论】:

标签: java unit-testing junit java-8


【解决方案1】:

如果您使用Mockito,对默认(又名“防御者”)方法进行单元测试的最简单方法是使用接口类文字创建spy12。然后可以照常在返回的 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,但自 @987654324 以来一直存在@ 于 2014 年发布。此外,support for default methods in Mockito 自 2016 年发布的 mockito-2.1.0 以来一直存在。似乎可以肯定的是,这种方法将在未来版本的 Mockito 中继续有效。 p>

【讨论】:

    【解决方案2】:

    按照答案中的建议,为接口创建实现类并对其进行测试,例如我在您的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;
        }
    }
    

    为此创建了一个实现类,您可以选择创建另一个调用超级方法的方法并为两者编写@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"));
        }
    }
    

    【讨论】:

    • 非常感谢。它奏效了。
    • @Jech 接受答案(如果有效)-meta.stackexchange.com/questions/5234/…
    • 嗨,我还有一个prblm,如何设置这个hashmap的值并模拟它 Map> uuidSourceMp = new HashMap(3);
    • 为它开一个单独的线程,不要将多个问题合二为一。
    • 我认为创建内部类或匿名类实现可能会更好地测试默认方法,因为将来实现可能会覆盖默认方法。
    【解决方案3】:

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

    界面)

    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....
    ...
    

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

    【讨论】:

      【解决方案4】:

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

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

      【讨论】:

        【解决方案5】:

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

        例如:

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2019-04-05
          • 1970-01-01
          • 2021-02-03
          • 1970-01-01
          • 2014-12-06
          • 2018-05-15
          • 2018-03-04
          • 1970-01-01
          相关资源
          最近更新 更多