This project is based on chapter 3.2. Using the @Autowired annotation to inject beans from book Spring Starts here (2021) by Laurentiu Spilca.
File > New project > Java
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>6.1.10</version>
</dependency>
public class Book {
private final String title;
private final Author author;
public Book(String title, Author author) {
this.title = title;
this.author = author;
}
public String getTitle() {
return title;
}
public Author getAuthor() {
return author;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null || getClass() != obj.getClass()) {
return false;
}
Book book = (Book) obj;
return title.equals(book.title) && author.equals(book.author);
}
@Override
public int hashCode() {
return title.hashCode() + author.hashCode();
}
}
public class Author {
private final String name;
public Author(String name) {
this.name = name;
}
public String getName() {
return name;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null || getClass() != obj.getClass()) {
return false;
}
Author author = (Author) obj;
return name.equals(author.name);
}
@Override
public int hashCode() {
return name.hashCode();
}
}
- use
@Repository
annotation to mark classes as bean
@Repository
public class AuthorRepository {
public Author getAuthor() {
return new Author("F. Scott Fitzgerald");
}
}
@Repository
public class BookRepository {
public Book getBook(Author author) {
return new Book("The Great Gatsby", author);
}
}
- use
@Autowired
annotation to injectBookRepository
through the class field - use
@Autowired
annotation to injectAuthorRepository
through the setter method - use
@Service
annotation to mark class as bean
@Service
public class BookService {
@Autowired
private BookRepository bookRepository;
private AuthorRepository authorRepository;
@Autowired
public void setAuthorRepository(AuthorRepository authorRepository) {
this.authorRepository = authorRepository;
}
public Book getBook() {
final Author author = authorRepository.getAuthor();
return bookRepository.getBook(author);
}
}
- use
@Autowired
annotation to injectBookService
through the constructor parameter - use
@Controller
annotation to mark class as bean
@Controller
public class BookController {
private final BookService bookService;
@Autowired
public BookController(BookService bookService) {
this.bookService = bookService;
}
public Book getBook() {
return bookService.getBook();
}
}
- use
@ComponentScan
annotation to configure component scan
@Configuration
@ComponentScan(basePackages = "org.example")
public class ApplicationConfiguration {
}
ApplicationContext context = new AnnotationConfigApplicationContext(ApplicationConfiguration.class);
Book book = context.getBean(BookController.class).getBook();
System.out.println("The book is: " + book.getTitle() + " by " + book.getAuthor().getName());
AuthorRepository
BookRepository
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.11.0-M2</version>
<scope>test</scope>
</dependency>
- use annotations
@Test
and@DisplayName
to mark test methods - use
assertEquals
method to compare expected and actual values
class AuthorRepositoryTest {
@Test
@DisplayName("Fetches the author")
void getAuthor() {
AuthorRepository authorRepository = new AuthorRepository();
Author actual = authorRepository.getAuthor();
Author expected = new Author("F. Scott Fitzgerald");
assertEquals(expected, actual);
}
}
- allows creating mock objects
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>5.12.0</version>
<scope>test</scope>
</dependency>
- allows to initialize mocks in JUnit 5 tests
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-junit-jupiter</artifactId>
<version>5.12.0</version>
<scope>test</scope>
</dependency>
- use
@ExtendWith(MockitoExtension.class)
annotation to add Mockito JUnit 5 support - use
@Mock
annotation to mark fields that should be mocked
@ExtendWith(MockitoExtension.class)
class BookServiceTest {
@Mock
private BookRepository bookRepository;
@Mock
private AuthorRepository authorRepository;
@Test
@DisplayName("Combines the author and book to get the book")
void getBook() {
given(authorRepository.getAuthor()).willReturn(new Author("author"));
given(bookRepository.getBook(new Author("author"))).willReturn(new Book("book", new Author("author")));
BookService bookService = new BookService(bookRepository, authorRepository);
Book actual = bookService.getBook();
Book expected = new Book("book", new Author("author"));
assertEquals(expected, actual);
}
}
Spring TestContext Framework provides support for loading Spring ApplicationContext and beans in tests.
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>6.1.10</version>
<scope>test</scope>
</dependency>
- use
@ExtendWith(SpringExtension.class)
annotation to add Spring TestContext Framework support - use
@ContextConfiguration
annotation to specify the configuration class
@ExtendWith(SpringExtension.class)
@ContextConfiguration(classes = ApplicationConfiguration.class)
public class IntegrationTest {
@Autowired
private BookController bookController;
@Test
void fetchesBook() {
Book actual = bookController.getBook();
Book expected = new Book("The Great Gatsby", new Author("F. Scott Fitzgerald"));
assertEquals(expected, actual);
}
}