如何创建用于重用某些测试的界面

时间:2019-01-15 14:03:08

标签: java junit interface mockito

我有一个spring项目,并且我正在使用Gradle,所以我用一些@Test创建了此接口,我想将其重用于测试其他类

import static org.junit.Assert.assertEquals;

import java.util.List;
import java.util.Optional;

import javax.persistence.Entity;

import org.junit.Before;
import org.junit.Test;
import org.mockito.Mockito;
import org.springframework.data.jpa.repository.JpaRepository;

public interface CrudTest<T> {


    public JpaRepository<T, Long> getRepository();

    public Crud<T> getService();

    public T getEntity();

    public List<T> getEntities();

    public default void asserts(T entity) {
        assertEquals(getEntity(), entity);
    }

    public default void asserts(List<T> entities) {
        List<T> idealEntities = getEntities();
        for (int i = 0; i < idealEntities.size(); i++) {
            assertEquals(idealEntities.get(i), entities.get(i));
        }
    }

    public default void setUp() {
        Mockito.when(getRepository().findAll()).thenReturn(getEntities());
        // Mocking others methods
        ....
    }

    @Test
    public default void create() {
        T entity = getService().create(getEntity());
        asserts(entity);
    }

    @Test
    public default void update() {
        T entity = getService().update(getEntity());
        asserts(entity);
    }

    @Test
    public default void retrieveOne() {
        T entity = getService().retrieve(1L);
        asserts(entity);
    }

    @Test
    public default void retrieveAll() {
        List<T> entities = getService().retrieve();
        asserts(entities);
    }
}

我正在这样实现此接口:

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

import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
import org.springframework.data.jpa.repository.JpaRepository;

@RunWith(MockitoJUnitRunner.class)
public class CountryServiceTest implements CrudTest<Country> {

    @InjectMocks
    private CountryService countryService;

    @Mock
    private CountryRepository countryRepository;

    @Override
    public JpaRepository<Country, Long> getRepository() {
        return countryRepository;
    }

    @Override
    public Crud<Country> getService() {
        return countryService;
    }

    @Override
    public Country getEntity() {
        Country country = new Country(1L, "UUEE");
        return country;
    }

    @Override
    public List<Country> getEntities() {
        List<Country> countries = new ArrayList<>();
        Country country = new Country(1L, "UUEE");
        countries.add(country);
        country = new Country(2L, "Canada");
        countries.add(country);
        return countries;
    }
}

像这样

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

import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
import org.springframework.data.jpa.repository.JpaRepository;

@RunWith(MockitoJUnitRunner.class)
public class CityServiceTest implements CrudTest<City> {

    @InjectMocks
    private CityService cityService;

    @Mock
    private CityRepository cityRepository;

    @Override
    public JpaRepository<City, Long> getRepository() {
        return cityRepository;
    }

    @Override
    public Crud<City> getService() {
        return cityService;
    }

    @Override
    public City getEntity() {
        City city = new City(1L, "New York", new Department());
        return city;
    }

    @Override
    public List<City> getEntities() {
        List<City> cities = new ArrayList<>();
        City city = new City(1L, "New York", new Department());
        cities.add(city);
        city = new City(2L, "Boston", new Department());
        cities.add(city);
        return cities;
    }
}

如您所见,我想测试几个@Service来创建,检索,更新和删除(CRUD)。但这基本上是相同的,我的意思是模拟存储库以测试创建,检索和所有这些东西的方法,因此这就是原因,因为我想创建一个接口并将相同的东西放在那里。但是我遇到了一个错误,因为在我的类CityServiceTest和CountryServiceTest中,我没有带@Test批注的方法。我得到的错误是这样的:

java.lang.Exception: No runnable methods
    at org.junit.runners.BlockJUnit4ClassRunner.validateInstanceMethods(BlockJUnit4ClassRunner.java:191)
    at org.junit.runners.BlockJUnit4ClassRunner.collectInitializationErrors(BlockJUnit4ClassRunner.java:128)
    at org.junit.runners.ParentRunner.validate(ParentRunner.java:416)
    at org.junit.runners.ParentRunner.<init>(ParentRunner.java:84)
    at org.junit.runners.BlockJUnit4ClassRunner.<init>(BlockJUnit4ClassRunner.java:65)
    at org.mockito.internal.runners.DefaultInternalRunner$1.<init>(DefaultInternalRunner.java:28)
    at org.mockito.internal.runners.DefaultInternalRunner.<init>(DefaultInternalRunner.java:28)
    at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:490)
    at org.mockito.internal.runners.util.RunnerProvider.newInstance(RunnerProvider.java:27)
    at org.mockito.internal.runners.RunnerFactory.create(RunnerFactory.java:69)
    at org.mockito.internal.runners.RunnerFactory.createStrict(RunnerFactory.java:40)
    at org.mockito.junit.MockitoJUnitRunner.<init>(MockitoJUnitRunner.java:154)
    at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:490)
    at org.junit.internal.builders.AnnotatedBuilder.buildRunner(AnnotatedBuilder.java:104)
    at org.junit.internal.builders.AnnotatedBuilder.runnerForClass(AnnotatedBuilder.java:86)
    at org.junit.runners.model.RunnerBuilder.safeRunnerForClass(RunnerBuilder.java:59)
    at org.junit.internal.builders.AllDefaultPossibilitiesBuilder.runnerForClass(AllDefaultPossibilitiesBuilder.java:26)
    at org.junit.runners.model.RunnerBuilder.safeRunnerForClass(RunnerBuilder.java:59)
    at org.junit.internal.requests.ClassRequest.getRunner(ClassRequest.java:33)
    at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.runTestClass(JUnitTestClassExecutor.java:78)
    at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.execute(JUnitTestClassExecutor.java:58)
    at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.execute(JUnitTestClassExecutor.java:38)
    at org.gradle.api.internal.tasks.testing.junit.AbstractJUnitTestClassProcessor.processTestClass(AbstractJUnitTestClassProcessor.java:66)
    at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.processTestClass(SuiteTestClassProcessor.java:51)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:566)
    at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:35)
    at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
    at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:32)
    at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:93)
    at com.sun.proxy.$Proxy2.processTestClass(Unknown Source)
    at org.gradle.api.internal.tasks.testing.worker.TestWorker.processTestClass(TestWorker.java:118)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:566)
    at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:35)
    at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
    at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:175)
    at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:157)
    at org.gradle.internal.remote.internal.hub.MessageHub$Handler.run(MessageHub.java:404)
    at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:63)
    at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:46)
    at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
    at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
    at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:55)
    at java.base/java.lang.Thread.run(Thread.java:834)

因此,我想知道是否可以使用接口,或者是否必须在每个特定的类中重复测试。非常感谢您的建议,

1 个答案:

答案 0 :(得分:0)

@Test没有标记为@Inherited,因此您的实现类将不包含任何带有@Test注释的方法。

应该可以创建自己的继承自测试的注释:

@Inherited
@Test
@Retention(value=RUNTIME)
@Target(value=METHOD)
public @interface AbstractTest