简体   繁体   中英

How to test generic abstract class with @Autowired fields?

I have generic abstract class AbstractBaseEntityGenericDao which contains @Autowired field. It worked perfectly until I had to write a unit test for it, to not duplicate the same code inside all tests for classes which extends it. And now I'm thinking...Is it possible to write a unit/integration test for such class?

@Repository
@Transactional
public abstract class AbstractBaseEntityGenericDao<T extends BaseEntity> {

    private Class<T> classInstance;

    private SessionFactory sessionFactory;

    @Autowired
    public void setSessionFactory(SessionFactory sessionFactory) {
        this.sessionFactory = sessionFactory;
    }

    public final void setClassInstance(Class<T> clasInstance) {
        this.classInstance = clasInstance;
    }

    public void create(@NonNull T entity) {
        Session session = sessionFactory.getCurrentSession();
        session.save(entity);
    }

    public Optional<T> find(long id) {
        Session session = sessionFactory.getCurrentSession();
        return Optional.ofNullable(session.get(classInstance, id));
    }

    public void update(@NonNull T entity) {
        Session session = sessionFactory.getCurrentSession();
        session.saveOrUpdate(entity);
    }

    public void remove(@NonNull Long id) throws EntityNotFoundException {
        Session session = sessionFactory.getCurrentSession();
        session.remove(session.load(classInstance, id));
    }

    public void remove(@NonNull T entity) {
        Session session = sessionFactory.getCurrentSession();
        session.remove(entity);
    }
}

The reason this is difficult is because generally you should not be doing this. The abstract class should have no knowledge of how its child creates SessionFactory . so instead it should look something like:

@Repository
@Transactional
public abstract class AbstractBaseEntityGenericDao<T extends BaseEntity> {

    ...        

    protected SessionFactory sessionFactory;

    ...
}

Now you CANNOT directly unit test a abstract class as it can not be instantiated. you can however stub it out in a unit test, and test that stub. The stub in turn will have a constructor for the protected field which we can mock out in the unit test. In the end it would look like:

public class AbstractBaseEntityGenericDaoTest {

    private class AbstractClassStub extends AbstractBaseEntityGenericDao {

        public AbstractClassStub(SessionFactory sessionFactory) {
            this.sessionFactory = sessionFactory;
        }

        @Override
        public void create(BaseEntity entity) {
            super.create(entity);
        }

        @Override
        public Optional find(long id) {
            return super.find(id);
        }

        @Override
        public void update(BaseEntity entity) {
            super.update(entity);
        }

        @Override
        public void remove(@NonNull Long id) throws EntityNotFoundException {
            super.remove(id);
        }

        @Override
        public void remove(BaseEntity entity) {
            super.remove(entity);
        }
    }

    @Mock
    SessionFactory sessionFactory;

    private AbstractClassStub abstractClassStub;

    @Before
    public void before() {
        sessionFactory = mock(SessionFactory.class);
        abstractClassStub = new AbstractClassStub(sessionFactory);
    }

    @Test
    public void testWhatever() {
        abstractClassStub.find(1); //or whatever
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM