Home > Back-end >  How to enable @Autowired annotation in tests using JUnit 5
How to enable @Autowired annotation in tests using JUnit 5

Time:09-28

So i have my word repository and want to check if it works as i expected. But honestly i am not really into it, this is my first try of writing such tests, so i am not sure what i should add to my project to make it work correctly

Here is my Repository interface :

package com.similiz.dictionary.repository;

import com.similiz.dictionary.entity.SameWords;
import com.similiz.dictionary.entity.Word;

import java.util.List;

public interface WordRepository {
    List<Word> findAll();

    Word findById(long id);

    List<Word> findSameWords(Word word);

    SameWords findSameWordsById(long id);

    <T extends Word> List<T> saveAll(Iterable<T> words);

    void save(Word word);

    void deleteAll();

    void deleteById(long id);
}

Here is my Repository interface implementation :

package com.similiz.dictionary.repository;

import com.similiz.dictionary.entity.SameWords;
import com.similiz.dictionary.entity.Word;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.query.Query;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

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

@Repository
public class WordRepositoryImplementation implements WordRepository {

    @Autowired
    private SessionFactory sessionFactory;

    @Override
    public List<Word> findAll() {
        Session session = sessionFactory.getCurrentSession();
        Query<Word> wordQuery = session.createQuery("select w from Word w", Word.class);
        return wordQuery.getResultList();
    }

    @Override
    public Word findById(long id) {
        Session session = sessionFactory.getCurrentSession();
        return session.get(Word.class, id);
    }

    @Override
    public List<Word> findSameWords(Word word) {
        Session session = sessionFactory.getCurrentSession();
        Query<Word> wordQuery = session
                .createQuery("select sw.word2 from SameWords sw where sw.word1.id = :id", Word.class)
                .setParameter("id", word.getId());
        return wordQuery.getResultList();
    }

    @Override
    public SameWords findSameWordsById(long id) {
        Session session = sessionFactory.getCurrentSession();
        return session.get(SameWords.class, id);
    }

    @Override
    public <T extends Word> List<T> saveAll(Iterable<T> words) {
        Session session = sessionFactory.getCurrentSession();
        List<T> wordsList = new ArrayList<>();
        for (T word : words) {
            session.save(word);
            wordsList.add(word);
        }
        return wordsList;
    }

    @Override
    public void save(Word word) {
        Session session = sessionFactory.getCurrentSession();
        session.saveOrUpdate(word);
    }

    @Override
    public void deleteAll() {
        Session session = sessionFactory.getCurrentSession();
        session.createQuery("delete from Word").executeUpdate();
    }

    @Override
    public void deleteById(long id) {
        Session session = sessionFactory.getCurrentSession();
        session.createQuery("delete from Word w where w.id = :id")
                .setParameter("id", id).executeUpdate();
    }
}

Here is my Repository interface implementation test :

package com.similiz.dictionary.repository;

import com.similiz.dictionary.entity.Word;
import com.similiz.dictionary.util.ConnectionManager;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;

import static org.junit.jupiter.api.Assertions.assertSame;

class WordRepositoryImplementationTest {

    @Autowired
    private WordRepository wordRepository;

    @Test
    void returnNullIfWordsTableIsEmpty() {
        String sql = "select * from dictionary.words";
        try (Connection connection = ConnectionManager.open();
             Statement statement = connection.createStatement()) {
            System.out.println(connection.getTransactionIsolation());
            ResultSet resultSet = statement.executeQuery(sql);

            List<Word> wordList = new ArrayList<>();
            while (resultSet.next()) {
                Word word = new Word();
                word.setId(resultSet.getLong("id"));
                word.setName(resultSet.getString("name"));
                wordList.add(word);
            }

            List<Word> wordRepositoryFindAllMethodResult = wordRepository.findAll();

            assertSame(wordRepositoryFindAllMethodResult, wordList);

        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }
}

Here is my pom file :

<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>com.similiz.dictionary</groupId>
  <artifactId>WordsLibrary</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>war</packaging>

  <name>WordsLibrary Maven Webapp</name>
  <!-- FIXME change it to the project's website -->
  <url>https://www.example.com</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
  </properties>

  <dependencies>
    <!-- https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter-api -->
    <dependency>
      <groupId>org.junit.jupiter</groupId>
      <artifactId>junit-jupiter-api</artifactId>
      <version>5.9.0</version>
      <scope>test</scope>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-webmvc</artifactId>
      <version>5.3.22</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>javax.servlet-api</artifactId>
      <version>4.0.1</version>
      <scope>provided</scope>
    </dependency>
    <!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-databind</artifactId>
      <version>2.13.4</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.hibernate/hibernate-core -->
    <dependency>
      <groupId>org.hibernate</groupId>
      <artifactId>hibernate-core</artifactId>
      <version>5.6.11.Final</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>8.0.30</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/com.mchange/c3p0 -->
    <dependency>
      <groupId>com.mchange</groupId>
      <artifactId>c3p0</artifactId>
      <version>0.9.5.5</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.springframework/spring-orm -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-orm</artifactId>
      <version>5.3.22</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
    <dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
      <version>1.18.24</version>
      <scope>provided</scope>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
    <dependency>
      <groupId>org.aspectj</groupId>
      <artifactId>aspectjweaver</artifactId>
      <version>1.9.9.1</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-api -->
    <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>slf4j-api</artifactId>
      <version>2.0.1</version>
    </dependency>
  </dependencies>

  <build>
    <finalName>WordsLibrary</finalName>
    <pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
      <plugins>
        <plugin>
          <artifactId>maven-clean-plugin</artifactId>
          <version>3.1.0</version>
        </plugin>
        <!-- see http://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_war_packaging -->
        <plugin>
          <artifactId>maven-resources-plugin</artifactId>
          <version>3.0.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-compiler-plugin</artifactId>
          <version>3.8.0</version>
        </plugin>
        <plugin>
          <artifactId>maven-surefire-plugin</artifactId>
          <version>2.22.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-war-plugin</artifactId>
          <version>3.2.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-install-plugin</artifactId>
          <version>2.5.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-deploy-plugin</artifactId>
          <version>2.8.2</version>
        </plugin>
      </plugins>
    </pluginManagement>
  </build>
</project>

CodePudding user response:

Two obvious solutions to your problem.

First would be to explore the wonderful testing facilities baked in by either Spring, or SpringBoot (if you are using those extensions). SpringRunnerTests (or their spring-framework equivalent) are fairly straight forward to setup and plenty of tutorials exist (ref: https://www.baeldung.com/spring-boot-testing). The downside of this approach is that those test-frameworks usually spin up a full spring-container in order to execute, making them 'slow', albeit you get all the capabilities of the entire container.

Second option would be to use a mocking framework - my personal favorite is JMockit, but many will utilize Mockito instead - either is fine. In the mocking world, you are providing synthetic implementations (i.e. mocks) so as to test some classes behavior without needing full blown direct and transitive dependencies. e.g. your 'implementation' class could utilize a mock for the SessionFactory. Mocking is its own topic that you can easily research.

Last comment... Mocks belong at the bottom of the test-pyramid whereas spring-runner tests belong at the top. You sort of need both and likely a whole lot more mock-tests (to verify all the pathhways through the code, etc) whereas the spring-runner test is a small (perhaps only 1 test for the whole app) that demonstrates that the app itself works (e.g. golden path)

CodePudding user response:

Thanks to Jeff Bennett I found solution pretty fast. I had to change pom file dependencies and add more annotations to WordRepositoryImplementationTest

Here is my updated pom file:

<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>com.similiz.dictionary</groupId>
  <artifactId>WordsLibrary</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>war</packaging>

  <name>WordsLibrary Maven Webapp</name>
  <!-- FIXME change it to the project's website -->
  <url>https://www.example.com</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
  </properties>

  <dependencies>
    <!-- https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter-api -->
    <dependency>
      <groupId>org.junit.jupiter</groupId>
      <artifactId>junit-jupiter</artifactId>
      <version>5.9.1</version>
      <scope>test</scope>
    </dependency>

    <!-- https://mvnrepository.com/artifact/org.junit.platform/junit-platform-launcher -->
    <dependency>
      <groupId>org.junit.platform</groupId>
      <artifactId>junit-platform-launcher</artifactId>
      <version>1.9.0</version>
      <scope>test</scope>
    </dependency>

    <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-test -->
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-test</artifactId>
      <version>2.7.3</version>
      <scope>test</scope>
    </dependency>

    <dependency>
      <groupId>com.h2database</groupId>
      <artifactId>h2</artifactId>
      <version>2.1.214</version>
      <scope>test</scope>
    </dependency>

    <dependency>
      <groupId>org.assertj</groupId>
      <artifactId>assertj-core</artifactId>
      <version>3.23.1</version>
    </dependency>

    <!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-webmvc</artifactId>
      <version>5.3.22</version>
    </dependency>

    <!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>javax.servlet-api</artifactId>
      <version>4.0.1</version>
      <scope>provided</scope>
    </dependency>

    <!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-databind</artifactId>
      <version>2.13.4</version>
    </dependency>

    <!-- https://mvnrepository.com/artifact/org.hibernate/hibernate-core -->
    <dependency>
      <groupId>org.hibernate</groupId>
      <artifactId>hibernate-core</artifactId>
      <version>5.6.11.Final</version>
    </dependency>

    <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>8.0.30</version>
    </dependency>

    <!-- https://mvnrepository.com/artifact/com.mchange/c3p0 -->
    <dependency>
      <groupId>com.mchange</groupId>
      <artifactId>c3p0</artifactId>
      <version>0.9.5.5</version>
    </dependency>

    <!-- https://mvnrepository.com/artifact/org.springframework/spring-orm -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-orm</artifactId>
      <version>5.3.22</version>
    </dependency>

    <!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
    <dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
      <version>1.18.24</version>
      <scope>provided</scope>
    </dependency>

    <!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
    <dependency>
      <groupId>org.aspectj</groupId>
      <artifactId>aspectjweaver</artifactId>
      <version>1.9.9.1</version>
    </dependency>

    <!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-api -->
    <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>slf4j-api</artifactId>
      <version>2.0.1</version>
    </dependency>

    <!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-reload4j -->
    <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>slf4j-reload4j</artifactId>
      <version>2.0.2</version>
      <scope>test</scope>
    </dependency>

<!--    &lt;!&ndash; https://mvnrepository.com/artifact/commons-io/commons-io &ndash;&gt;-->
<!--    <dependency>-->
<!--      <groupId>commons-io</groupId>-->
<!--      <artifactId>commons-io</artifactId>-->
<!--      <version>2.11.0</version>-->
<!--    </dependency>-->

    <dependency>
      <groupId>org.jetbrains</groupId>
      <artifactId>annotations</artifactId>
      <version>23.0.0</version>
      <scope>compile</scope>
    </dependency>
  </dependencies>

  <build>
    <finalName>WordsLibrary</finalName>
    <pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
      <plugins>
        <plugin>
          <artifactId>maven-clean-plugin</artifactId>
          <version>3.1.0</version>
        </plugin>
        <!-- see http://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_war_packaging -->
        <plugin>
          <artifactId>maven-resources-plugin</artifactId>
          <version>3.0.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-compiler-plugin</artifactId>
          <version>3.8.0</version>
        </plugin>
        <plugin>
          <artifactId>maven-surefire-plugin</artifactId>
          <version>2.22.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-failsafe-plugin</artifactId>
          <version>2.22.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-war-plugin</artifactId>
          <version>3.2.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-install-plugin</artifactId>
          <version>2.5.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-deploy-plugin</artifactId>
          <version>2.8.2</version>
        </plugin>
      </plugins>
    </pluginManagement>
  </build>
</project>

as you can see i added more dependencies for testing:

<!-- https://mvnrepository.com/artifact/org.junit.platform/junit-platform-launcher -->
<dependency>
  <groupId>org.junit.platform</groupId>
  <artifactId>junit-platform-launcher</artifactId>
  <version>1.9.0</version>
  <scope>test</scope>
</dependency>

<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-test -->
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-test</artifactId>
  <version>2.7.3</version>
  <scope>test</scope>
</dependency>

<dependency>
  <groupId>com.h2database</groupId>
  <artifactId>h2</artifactId>
  <version>2.1.214</version>
  <scope>test</scope>
</dependency>

<dependency>
  <groupId>org.assertj</groupId>
  <artifactId>assertj-core</artifactId>
  <version>3.23.1</version>
</dependency>

Here is my updated test class:

@ExtendWith(SpringExtension.class)
@SpringBootTest(classes = {Config.class})
@Transactional
@TestInstance(value = TestInstance.Lifecycle.PER_METHOD)
class WordRepositoryImplementationTest {

    @Autowired
    private WordRepository wordRepository;

    // tests
}

P.S. My main problem was with pom file build because i tried such annotations before and i got some errors, which i am not remember for now, but Jeff Bennetts link should be helpful enough.

Full project code you can find by the link in my question

  • Related