3

im new on this of unit tests, so im trying to code the unit test for my service, right now i have this class

package com.praxis.topics.service;
import com.praxis.topics.exception.EntityNotFoundException;
import com.praxis.topics.model.Topic;
import com.praxis.topics.model.enums.Status;
import com.praxis.topics.repository.TopicRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
import java.util.List;

@Service("topics")
public class TopicServiceImpl implements TopicService {
   private final TopicRepository topicRepository;

   @Autowired
   public TopicServiceImpl(TopicRepository topicRepository) {
       this.topicRepository = topicRepository;
   }

   @Override
   public List<Topic> getTopicsByStatus(int status) {
       // Check if status exists in enum
       if (status < 0 || Status.values().length - 1 < status)
           throw new ArrayIndexOutOfBoundsException(status);

       return topicRepository.findTopicByStatus(Status.values()[status]);
   }

   @Override
   public Topic addTopic(Topic topic) {

       //topic.setCreatedAt(LocalDateTime.now());
       return topicRepository.save(topic);
   }

   @Override
   public Topic updateTopic(Topic topic) throws EntityNotFoundException {
       if (topicRepository.findTopicById(topic.getId()) == null)
           throw new EntityNotFoundException(String.format("Topic with    id:             %s was not found", topic.getId()));

           return topicRepository.save(topic);
   }

   @Override
   public Topic getTopicById(String id) {
       return topicRepository.findTopicById(id);
   }

   @Override
   public void deleteTopicById(String id) {
      topicRepository.deleteTopicById(id);
   }

   @Override
   public List<Topic> getTopicsByName(String name) {
      return topicRepository.findAllByNameContains(name);
   }

   @Override
   public Topic getTopicByName(String name) {
      return topicRepository.findTopicByName(name);
   }

   @Override
   public List<Topic>getAllTopics(){
      return topicRepository.findAll();
   }

}

the model of topics is this

package com.praxis.topics.model;
import com.praxis.topics.model.enums.Status;
import org.hibernate.validator.constraints.NotEmpty; 
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDateTime;

@Document(collection = "Topic")
public class Topic {
    @Id
    private String id;

    @NotEmpty(message = "The name is required")
    private String name;

    @NotEmpty(message = "The description is required")
    private String description;

    private Status status;
    private String chat;
    private int teachers;
    private int students;

    @DateTimeFormat(pattern = "dd-MM-yyyy hh:mm:ss")
    private LocalDateTime createdAt;

    @DateTimeFormat(pattern = "dd-MM-yyyy hh:mm:ss")
    private LocalDateTime openedAt;

    @DateTimeFormat(pattern = "dd-MM-yyyy hh:mm:ss")
    private LocalDateTime closedAt;

    public Topic() {}

    public Topic(String name, String description) {
        this.name = name;
        this.description = description;
        this.createdAt = LocalDateTime.now();
    }

and im trying to do this test for but it throws me a null pointer exception, like if the service variable wasnt initialized or something

package com.praxis.topics.service; 
import com.praxis.topics.model.Topic;
import com.praxis.topics.repository.TopicRepository;
import org.springframework.beans.factory.annotation.Autowired;
import static org.junit.jupiter.api.Assertions.*;

class TopicServiceImplTest {

   @Autowired
   TopicServiceImpl service;

   @org.junit.jupiter.api.Test
   void addTopic() {
       Topic topic = new Topic("java", "test");
       assertEquals(topic, service.addTopic(topic));
   }
}

and this are the exceptions i get

java.lang.NullPointerException at   com.praxis.topics.service.TopicServiceImplTest.addTopic(TopicServiceImplTest.java:29)
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:564)
at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:436)
at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:115)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$6(TestMethodTestDescriptor.java:170)
at org.junit.jupiter.engine.execution.ThrowableCollector.execute(ThrowableCollector.java:40)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:166)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:113)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:58)
at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.lambda$executeRecursively$3(HierarchicalTestExecutor.java:112)
at org.junit.platform.engine.support.hierarchical.SingleTestExecutor.executeSafely(SingleTestExecutor.java:66)
at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.executeRecursively(HierarchicalTestExecutor.java:108)
at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.execute(HierarchicalTestExecutor.java:79)
at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.lambda$executeRecursively$2(HierarchicalTestExecutor.java:120)
at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:184)
at java.base/java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:177)
at java.base/java.util.Iterator.forEachRemaining(Iterator.java:133)
at java.base/java.util.Spliterators$IteratorSpliterator.forEachRemaining(Spliterators.java:1801)
at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:484)
at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474)
at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:151)
at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:174)
at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
at java.base/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:430)
at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.lambda$executeRecursively$3(HierarchicalTestExecutor.java:120)
at org.junit.platform.engine.support.hierarchical.SingleTestExecutor.executeSafely(SingleTestExecutor.java:66)
at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.executeRecursively(HierarchicalTestExecutor.java:108)
at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.execute(HierarchicalTestExecutor.java:79)
at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.lambda$executeRecursively$2(HierarchicalTestExecutor.java:120)
at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:184)
at java.base/java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:177)
at java.base/java.util.Iterator.forEachRemaining(Iterator.java:133)
at java.base/java.util.Spliterators$IteratorSpliterator.forEachRemaining(Spliterators.java:1801)
at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:484)
at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474)
at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:151)
at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:174)
at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
at java.base/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:430)
at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.lambda$executeRecursively$3(HierarchicalTestExecutor.java:120)
at org.junit.platform.engine.support.hierarchical.SingleTestExecutor.executeSafely(SingleTestExecutor.java:66)
at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.executeRecursively(HierarchicalTestExecutor.java:108)
at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.execute(HierarchicalTestExecutor.java:79)
at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:55)
at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:43)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:170)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:154)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:90)
at com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:65)
at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)

any idea? i think that its because some of the variable dont get initialized, but im doing adding the @Autowired on those so i dont know what it is

this is my pom file

http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0

<groupId>com.praxis</groupId>
<artifactId>topics</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>

<name>topics</name>
<description>Project for Integrador 2018</description>

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>1.5.10.RELEASE</version>
    <relativePath/> <!-- lookup parent from repository -->
</parent>

<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    <java.version>1.8</java.version>
</properties>

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-mongodb</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-rest</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.springframework.restdocs</groupId>
        <artifactId>spring-restdocs-mockmvc</artifactId>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.datatype</groupId>
        <artifactId>jackson-datatype-jsr310</artifactId>
        <version>${jackson.version}</version>
    </dependency>
    <dependency>
        <groupId>org.junit.jupiter</groupId>
        <artifactId>junit-jupiter-api</artifactId>
        <version>RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-test</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-test</artifactId>
        <version>RELEASE</version>
    </dependency>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
    </dependency>
    <dependency>
        <groupId>org.assertj</groupId>
        <artifactId>assertj-core</artifactId>
    </dependency>
</dependencies>

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
    </plugins>
</build>

4
  • it seems you are doing the test without any Spring IoC initialized. So the dependencies are not injected into the service. Commented Mar 18, 2018 at 11:58
  • how do i do that? there's my pom file :/ Commented Mar 18, 2018 at 12:28
  • You must change your test file, for example add @Runner(SpringRunner.class) on the class. Commented Mar 18, 2018 at 20:23
  • The SpringRunner only works with JUnit 4. To use the Spring TestContext Framework with JUnit Jupiter (a.k.a., JUnit 5), you have to use the SpringExtension: @ExtendWith(SpringExtension.class) Commented Mar 21, 2018 at 12:14

3 Answers 3

3

For starters, if you're using JUnit Jupiter (the programming model in JUnit 5), you'll have to configure the Jupiter Test Engine in your build.

I recommend you use the official spring-boot-sample-junit-jupiter sample project as a template.

The pom.xml shows how to configure the Jupiter Test Engine with the Maven Surefire Plugin:

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-surefire-plugin</artifactId>
            <dependencies>
                <dependency>
                    <groupId>org.junit.platform</groupId>
                    <artifactId>junit-platform-surefire-provider</artifactId>
                    <version>${junit-platform.version}</version>
                </dependency>
            </dependencies>
        </plugin>
    </plugins>
</build>

Note that it also shows that you need dependency declarations for junit-jupiter-api and junit-jupiter-engine.

And SampleJunitJupiterApplicationTests shows how to configure Spring Boot's testing support with the SpringExtension for JUnit Jupiter:

@ExtendWith(SpringExtension.class)
@SpringBootTest
class TopicServiceImplTest {

  @Autowired
  TopicService service;

  // ..

}
Sign up to request clarification or add additional context in comments.

Comments

1

We had recently started using Spring 4.3, JUnit5, Maven together as well and got NullPointerException in integration tests where @Autowired was used.

Solution for us was to upgrade maven-related test dependencies:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-failsafe-plugin</artifactId>
    <version>3.0.0-M4</version>      // upgraded from 2.19.1
</plugin>
<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-surefire-plugin</artifactId>
    <version>3.0.0-M4</version>      // upgraded from 2.19
</plugin>

Comments

-1

Your TopicServiceImplTest class is not spring component so @Autowired won't work. Spring Boot test should be annotated with @SpringBootTest and @RunWith(SpringRunner.class). Optionaly you could use other annotations to define your context to suit your specific needs. You can find basic information here: https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-testing.html

3 Comments

i've tried adding those beans too ( @RunWith(SpringRunner.class) and @SpringBootTest ) before the class definition but error is still there.
The question is about JUnit 5, not JUnit 4.
The SpringRunner only works with JUnit 4. To use the Spring TestContext Framework with JUnit Jupiter (a.k.a., JUnit 5), you have to use the SpringExtension: @ExtendWith(SpringExtension.class)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.