1-Spring Boot Productapp Application Jan 25
1-Spring Boot Productapp Application Jan 25
___________________________
Key topics:
==================
=> Understand Depdendency Injection
=> bean wiring :xml, annoation, java configuraton
=> Spring boot aop
=> spring mvc basics
=> REST basics
=> Spring boot REST application
=> Spring AOP
=> Spring JDBCTemplate
=> Spring data
=> Spring boot web application, Spring MVC arch
=>Spring boot Monotring and Logging
=> Spring boot security
=> spring boot profile
=> spring boot actuator
=> spring boot jdbcTemplate
=> Spring Boot microservice architecture
=> spring boot openfeign
Day 1: session 1:
____________________
Rest
Controller <------------ Service layer <---------- persistance layer <------
SessionFactory
as we have design our application as per interface and we have use DI therefore
kapil team can change implemenation
of service layer ( let earlier they are using Jdbc now wnat to use hibernate )
without effectiving even a single line
of code in Service layer (sumit team) do you not think it is great...
beside that spring DI help to manage dependency of our project and make our project
flexiable
---------- ProductDaoImplHib
|
ProductService <---------------- ProductDao-------ProductDaoImplJdbc
|
---------- ProductDaoImplUtil
public ProductServiceImpl(){
productDao=new ProductDaoImplUtil(); // or ProductDaoImplJdbc()
}
public List<Product>getProducts(){
// business logic
}
}
* ApplicationContext
- more powerful
ApplicationContext applicationContext=
new ClassPathXmlApplicationContext("demo.xml");
ApplicationContext
-ClassPathXmlApplicationContext
-FileSystemXmlApplicationContext
-AnnotationConfigApplicationContext
-XMLWebApplicationContext
consider: we need to find how much time it take to execute code of service layer
and do logging into a log file
public ProductServiceImpl(){
productDao=new ProductDaoImplUtil(); // or ProductDaoImplJdbc()
}
public List<String>getProducts(){
//how much it take to execute and do logging too ....
// business logic
}
}
session 2:
___________
MVC design pattern
=> Auto-Configuration
=> Microservice
@SpringBootApplication
public class Application {
spring-boot:run
@Component
public class ApplicationRunnerBean implements ApplicationRunner {
@Override
public void run(ApplicationArguments args) throws Exception {
String collectStr =
Arrays.stream(args.getSourceArgs()).collect(Collectors.joining(","));
System.out.println(collectStr);
}
}
https://www.concretepage.com/spring-boot/spring-boot-commandlinerunner-and-
applicationrunner-example#:~:text=The%20difference%20between%20CommandLineRunner
%20and,spring%20ApplicationArguments%20as%20an%20argument.&text=To%20execute%20them
%20in%20an,Order%20annotation%20or%20Ordered%20interface.
Hello world:
-----------
@RestController
public class HelloRestController {
@RequestMapping("/hello")
public String hello(){
return "spring boot";
}
}
@GetMapping("products/{id}")
public Book getProductById(@PathVariable(name = "id")int id) {
return new Product(id, "java basics book", new BigDecimal(300));
}
application.properties
---------------------------
server.servlet.context-path=/productapp
server.port=8080
Running spring boot :
____________________
eclipse plugin
spring initilizer
spring cli
https://www.journaldev.com/8195/spring-boot-cli-setup-and-helloworld-example
bannner:
________________
spring.banner.location=classpath:banner.txt
https://devops.datenkollektiv.de/banner.txt/index.html
https://docs.spring.io/spring-boot/docs/1.1.2.RELEASE/reference/html/common-
application-properties.html
@Configuration
@EnableAutoConfiguration(exclude = {DataSourceAutoConfiguration.class,
DataSourceTransactionManagerAutoConfiguration.class,
HibernateJpaAutoConfiguration.class})
@Profile ("client_app_profile_name")
public class ClientAppConfiguration {
//it can be left blank
}
Day 2:
Rest
Controller <------------ Service layer <---------- persistance layer <------
SessionFactory
step 1: application.properties
_______________________
server.servlet.context-path=/productapp
server.port=8082
spring.datasource.url=jdbc:mysql://localhost:3306/demoms?useSSL=false
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.jpa.hibernate.ddl-auto=update
logging.level.org.springframework.web: DEBUG
logging.level.org.hibernate: ERROR
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.format_sql=true
in case of h2 database :
---------------------
server.port=8090
server.servlet.context-path=/productapp
spring.h2.console.enabled=true
spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=password
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
# Custom H2 Console URL
spring.h2.console.path=/h2
spring.jpa.hibernate.ddl-auto=update
logging.level.org.springframework.web: DEBUG
logging.level.org.hibernate: ERROR
spring.jpa.show-sql=true
@Repository
public interface ProductDao extends JpaRepository<Product, Integer>{
public Product findByName(String name);
}
@Service
@Transactional
public class ProductServiceImpl implements ProductService {
@Autowired
public ProductServiceImpl(ProductDao productDao) {
this.productDao = productDao;
}
@Override
public List<Product> findAll() {
return productDao.findAll();
}
@Override
public Product getById(int id) {
return productDao.findById(id)
.orElseThrow(() -> new ProductNotFoundException("product
with id" + id + " is not found"));
}
@Override
public Product addProduct(Product product) {
productDao.save(product);
return product;
}
@Override
public Product updateProduct(int id, Product product) {
Product productToUpdate= getById(id);
productToUpdate.setPrice(product.getPrice());
productDao.save(productToUpdate);
return productToUpdate;
}
@Override
public Product deleteProduct(int id) {
Product productToDelete= getById(id);
productDao.delete(productToDelete);
return productToDelete;
}
@Autowired
public ProductController(ProductService productService) {
this.productService = productService;
}
@GetMapping(path = "products")
public List<Product>findAll(){
return productService.findAll();
}
@GetMapping(path = "products/{id}")
public Product findById(@PathVariable(name = "id") int id){
return productService.getById(id);
}
@PostMapping(path = "products")
public Product addProduct( @RequestBody Product product){
return productService.addProduct(product);
}
@DeleteMapping(path = "products/{id}")
public Product deleteProduct(@PathVariable(name = "id") int id){
return productService.deleteProduct(id);
}
@PutMapping(path = "products/{id}")
public Product updateProduct(@PathVariable(name = "id") int id, @RequestBody
Product product){
return productService.updateProduct(id, product);
}
}
Let
@RestController
public class ProductController {
@Autowired
public ProductController(ProductService productService) {
this.productService = productService;
}
@GetMapping(path = "products")
public ResponseEntity<List<Product>> findAll(){
return
ResponseEntity.status(HttpStatus.OK).body(productService.findAll());
}
@GetMapping(path = "products/{id}")
public ResponseEntity<Product> findById(@PathVariable(name = "id") int id){
return ResponseEntity.ok(productService.getById(id));
}
@PostMapping(path = "products")
public ResponseEntity<Product> addProduct( @RequestBody Product product){
return
ResponseEntity.status(HttpStatus.CREATED).body(productService.addProduct(product));
}
@DeleteMapping(path = "products/{id}")
public ResponseEntity<Void> deleteProduct(@PathVariable(name = "id") int id){
productService.deleteProduct(id);
return ResponseEntity.status(HttpStatus.NO_CONTENT).build();
}
@PutMapping(path = "products/{id}")
public ResponseEntity<Product> updateProduct(@PathVariable(name = "id") int
id, @RequestBody Product product){
return
ResponseEntity.status(HttpStatus.CREATED).body(productService.updateProduct(id,
product));
}
}
Step 6: rest controller exception handling
_______________________________________
@ResponseStatus(code =HS.NotFound)
ProductNotFoundException extends RuntimeExcetion{
}
@Data
@NoArgsConstructor
@AllArgsConstructor
public class ErrorDetails {
private String message;
private String statusCode;
@RestControllerAdvice
public class ExHandlerController {
@ExceptionHandler(ProductNotFoundException.class)
public ResponseEntity<ErrorDetails> handle404(ProductNotFoundException ex){
ErrorDetails details=new ErrorDetails();
details.setLocalDateTime(LocalDateTime.now());
details.setMessage(ex.getMessage());
details.setName("[email protected]");
details.setStatusCode(HttpStatus.NOT_FOUND.toString());
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(details);
}
@ExceptionHandler(Exception.class)
public ResponseEntity<ErrorDetails> handle500(Exception ex){
ErrorDetails details=new ErrorDetails();
details.setMessage(ex.getMessage());
details.setLocalDateTime(LocalDateTime.now());
details.setName("[email protected]");
details.setStatusCode(HttpStatus.INTERNAL_SERVER_ERROR.toString());
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(details);
}
}
3.
@Data
@NoArgsConstructor
@AllArgsConstructor
public class ProductDto {
@NotNull(message = "{product.name.absent}")
@Pattern(regexp = "[A-Za-z]+( [A-Za-z]+)*", message =
"{product.name.invalid}")
private String name;
@NotNull(message = "{product.price.absent}")
@Range(min = 100, max = 100000, message = "{product.price.invalid}")
private BigDecimal price;
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ExceptionHandler(MethodArgumentNotValidException.class)
public Map<String, String>
handleInvalidArgument(MethodArgumentNotValidException ex) {
ValidationMessages.properties
-----------------------------
@Email(message = "{account.email.invalid}")
@NotNull(message = "{account.email.absent}")
private String email;
@NotNull(message = "{account.phone.absent}")
@Pattern(regexp = "[789][0-9]{9}", message = "{account.phone.invalid}")
private String phone;
EL BOOKS FMCG
Implementation of custom valiation logic:
-------------------------------------------
@Target({ElementType.FIELD,ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Constraint(validatedBy = ProductTypeValidator.class)
public @interface ValidateProductType {
//custom annotation
@ValidateProductType
private String productType; //Electronic or Books
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
</dependency>
Step 2:
@GetMapping(path = "products", produces = {MediaType.APPLICATION_JSON_VALUE,
MediaType.APPLICATION_XML_VALUE})
spring boot reading property files:
---------------------------------
1. @Value annotation
2. Enviornment
3. @ConfigrationProperties
@EnableConfigurationProperties(InfoDto.class)
@ConfigrationProperties(prefix="db")
Example:
--------
account:
message: "welcome to productapp account manager"
contactDetails:
name: "raj"
email: "[email protected]"
onCallSupport:
-54645464556
-75765777677
@ConfigurationProperties(prefix = "account")
@Data
@NoArgsConstructor
@AllArgsConstructor
public class InfoDto {
private String message;
private Map<String, String>contactDetails;
private List<String>onCallSupport;
}
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>
Disable logging :
---------------
logging.level.root=OFF
logging.level.org.springframework.boot=OFF
spring.main.banner-mode=OFF
Customizing logging :
---------------
logging.level.org.springframework.web: DEBUG
logging.level.org.hibernate: ERROR
logging.level.com.productapp=info
logging.level.org.springframework.web: DEBUG
logging.level.org.hibernate: ERROR
logging.file.name=/home/raj/Desktop/logs/server.log
@GetMapping(path = "productsV2/{id}")
public EntityModel<Product> findByIdLink(@PathVariable(name = "id") int id){
Link
link=linkTo(methodOn(ProductController.class).findByIdLink(id)).withSelfRel();
Product product=productService.getById(id);
product.add(link);
return EntityModel.of(product);
}
@GetMapping(path = "productsV2")
public CollectionModel<Product> findAllV2(){
List<Product> products=productService.findAll();
for(Product product: products) {
Link
link=linkTo(methodOn(ProductController.class).findByIdLink(product.getId())).withSe
lfRel();
product.add(link);
}
return CollectionModel.of(products);
}
https://editor.swagger.io/
Step 1:
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
<version>2.2.0</version>
</dependency>
Step 2:
http://localhost:8090/bookapp/v3/api-docs
http://localhost:8090/bookapp/swagger-ui/index.html
http://localhost:8090/bookapp/v3/api-docs.yaml
Step 3:
Customization location
springdoc.swagger-ui.path=/swagger-ui-bookapp.html
@OpenAPIDefinition(
info = @Info(
title = "",
description = "",
version = "v1",
contact = @Contact(
name = "",
email = "",
url = ""
),
license = @License(
name = "Apache 2.0",
url = "https://www.cbre.com"
)
),
externalDocs = @ExternalDocumentation(
description = "",
url = "https://www.cbre.com/swagger-ui.html"
)
)
10. caching
_____________
1. In memory cache
-------------------
@Configuration
@EnableCaching
public class CachingConfig {
@Bean
public CacheManager cacheManager(){
ConcurrentMapCacheManager cacheManager=new
ConcurrentMapCacheManager("products");
return cacheManager;
}
}
@Slf4j
@Service
@Transactional
public class ProductServiceImpl implements ProductService {
@Cacheable(value="products")
@Override
public List<Product> findAll() {
//
}
@CachePut(value="products", key="#result.id")
@Override
public Product addProduct(Product product) {
//
}
@CachePut(value="products", key="#result.id")
@Override
public Product updateProduct(int id, Product product) {
//
}
@CacheEvict(value="products", key="#id")
@Override
public Product deleteProduct(int id) {
//
}
@CacheEvict(value="products", allEntries=true)
@Override
public void evictCache() {
log.info("cache is cleared...");
}
Note:
The simple rules that we need to follow to annotate a method with @Scheduled
are:
@Service
public class ScheduledJob {
private Logger logger =
LoggerFactory.getLogger(ScheduledJob.class);
@Autowired
private ProductService service;
@Scheduled(cron = "0,30 * * * * *")
public void cronJob() {
logger.info("> cronJob");
logger.info("< cronJob");
}
logger.info("< fixedRateJob");
}
ref:
https://www.baeldung.com/spring-scheduled-tasks
https://www.tutorialspoint.com/unix_commands/crontab.htm
server.port=8080
spring.devtools.restart.enabled=true
#management.endpoints.web.exposure.exclude=*
management.endpoints.web.exposure.include=health, custom-endpoint
management.endpoint.health.show-details=always
management.health.disk.enabled=true
management.health.livenessstate.enabled=true
management.health.readinessstate.enabled=true
management.server.port=9090
management.endpoint.info.enabled=true
management.endpoint.health.enabled=true
@Configuration
@Endpoint(id = "custom-endpoint")
public class CustomEndpoints {
@ReadOperation
public String getCustomData(){
return "This is custom Data";
}
}
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
</dependency>
spring.mvc.view.prefix:/WEB-INF/views/
spring.mvc.view.suffix:.jsp
3. define controller
@Controller
public class ProductController {
@Autowired
public ProductController(ProductService productService) {
this.productService = productService;
}
@GetMapping("products")
public ModelAndView allProducts(ModelAndView mv) {
mv.setViewName("products");
mv.addObject("products", productService.findAll());
return mv;
}
}
</body>
</html>
RDBMS MongoDB
______________
@Document(collection = "products")
public class Product {
@Id
private String id;
private String name;
private BigDecimal price;
private String category;
@Repository
public interface ProductRepo extends MongoRepository<Product, Integer> {
public List<Product> findByName(String name);
}
step 5: application.properties
___________________
server.servlet.context-path=/empapp
server.port=8080
spring.data.mongodb.host=localhost
spring.data.mongodb.port=27017
spring.data.mongodb.database=mongodb
spring.data.mongodb.repositories.enabled=true
Spring boot js
----------------
<script>
let data = fetch('http://localhost:8080/empapp/employee')
data.then((item) => {
return item.json();
}).then((result) => {
console.log(result);
})
</script>
Key terms
----------
Cache hit
Cache miss
System of record
Why caching??
---------------
Locality of reference
Speed
Cost saving
topology
-----------
Standalone
Distributed
Replicated
Storage tiers
--------------
Memory store – subject to GC
offHeap store – available upto RAM
Disk store
Configuration:
----------------
spring-boot-starter-cache
spring-boot-starter-web
spring-boot-starter-data-jpa
'net.sf.ehcache', name: 'ehcache', version: '2.10.6'
@Configuration
public class EhcacheConfig {
@Bean
CacheManager cacheManager(){
return new EhCacheCacheManager(ehCacheManager());
}
ehcache.xml
----------------
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="ehcache.xsd"
updateCheck="true"
monitoring="autodetect"
dynamicConfig="true"
diskPersistent="true">
<cache name="books"
maxEntriesLocalHeap="5"
maxEntriesLocalDisk="10"
eternal="false"
diskSpoolBufferSizeMB="20"
timeToIdleSeconds="3000"
timeToLiveSeconds="6000"
memoryStoreEvictionPolicy="LFU"
transactionalMode="off"
>
<persistence strategy="localTempSwap" />
<!-- <persistence strategy="LOCALRESTARTABLE" />-->
</cache>
</ehcache>
redis introduction:
-----------------
What is redis?
https://www.javatpoint.com/redis-tutorial
https://redis.io/clients
https://github.com/tporadowski/redis/releases
Redis as database?
------------------
step 1: add dependencies
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
import org.springframework.data.annotation.Id;
import org.springframework.data.redis.core.RedisHash
@RedisHash("Product")
public class Product implements Serializable {
@Id
private int id;
private String name;
private int qty;
private long price;
}
@Bean
public JedisConnectionFactory connectionFactory() {
RedisStandaloneConfiguration configuration = new
RedisStandaloneConfiguration();
configuration.setHostName("localhost");
configuration.setPort(6379);
return new JedisConnectionFactory(configuration);
}
@Bean
public RedisTemplate<String, Object> template() {
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(connectionFactory());
template.setKeySerializer(new StringRedisSerializer());
template.setHashKeySerializer(new StringRedisSerializer());
template.setHashKeySerializer(new JdkSerializationRedisSerializer());
template.setValueSerializer(new JdkSerializationRedisSerializer());
template.setEnableTransactionSupport(true);
template.afterPropertiesSet();
return template;
}
}
@Repository
public class ProductDao {
@Autowired
private RedisTemplate template;
Redis as Cache?
------------------
spring-boot-starter-data-redis
spring-boot-starter-web
spring-boot-starter-data-jpa
spring-boot-starter-data-jpa
spring.redis.host=localhost
spring.redis.port=6379
spring.redis.timeout=10000
spring.cache.type=REDIS
spring.redis.cache-null-values=false
spring.redis.use-key-prefix: true
spring.redis.key-prefix: library
spring.redis.time-to-live: 60000
https://github.com/tporadowski/redis/releases
6379
set the env variable
-----------imp property file configurations------------------
server.port=8090
server.servlet.context-path=/bankapp
spring.datasource.driver-class-name= com.mysql.jdbc.Driver
spring.jpa.properties.hibernate.dialect= org.hibernate.dialect.MySQL5InnoDBDialect
spring.jpa.hibernate.ddl-auto= update
spring.datasource.url=jdbc:mysql://localhost:3306/edu123?useSSL=false
spring.datasource.username=root
spring.datasource.password=root
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.format_sql=true
spring.jpa.hibernate.ddl-auto=update
logging.level.org.springframework.web: DEBUG
logging.level.org.hibernate: ERROR
logging.level.com.productapp: INFO
logging.level.com.productapp.service: INFO
spring.jpa.show-sql=true
spring.banner.location=
spring.jmx.enabled=true
management.endpoints.web.exposure.include=*
management.endpoints.jmx.exposure.include=*
management.info.env.enabled=true
info.app.encoding=UTF-8
info.app.java.source=21
info.app.java.target=21
info.app.name=productapp
info.app.dev=amit ku
management.endpoint.health.show-details=always
management.endpoint.health.probes.enabled=true
# livenessstate readinessstate
#management.health.livenessstate.enabled=true
#management.health.readinessstate.enabled=true
info.key=default
spring.profiles.active=test
server.port=8090
server.servlet.context-path=/productapp
spring.h2.console.enabled=true
spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=foo
spring.datasource.password=foo
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
spring.jpa.hibernate.ddl-auto=update
repo
import static org.assertj.core.api.Assertions.assertThat;
service
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
import static org.mockito.BDDMockito.given;
controller
import com.fasterxml.jackson.databind.ObjectMapper;
import com.productapp.repo.Product;
import com.productapp.service.ProductService;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.ResultActions;
import java.util.ArrayList;
import java.util.List;
integration layer
--------------
import com.fasterxml.jackson.databind.ObjectMapper;
import com.productapp.repo.Product;
import com.productapp.repo.ProductRepo;
import com.productapp.service.ProductService;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import
org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.ResultActions;
import java.util.ArrayList;
import java.util.List;
import static org.hamcrest.CoreMatchers.is;
import static
org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static
org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static
org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static
org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
spring.jpa.hibernate.ddl-auto=update
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.test.annotation.Rollback;
import java.util.List;
import java.util.Optional;
@Autowired
private ProductRepo productRepo;
private Product product;
@BeforeEach
void setUp() {
product=new Product("laptop", 120000);
}
@Test
@Rollback(value = true)
public void givenProductObjectWhenSaveReturnProductObject(){
Product productSaved=productRepo.save(product);
assertThat(productSaved).isNotNull();
assertThat(productSaved.getId()).isGreaterThan(0);
}
@DisplayName("JUnit test for get all employees operation")
@Test
public void givenProductList_whenFindAll_thenProductList(){
//given
Product p1=new Product("laptop",120000);
Product p2=new Product("laptop cover",1200);
productRepo.save(p1);
productRepo.save(p2);
// when - action or the behaviour that we are going test
List<Product> productList=productRepo.findAll();
// then - verify the output
assertThat(productList).isNotNull();
assertThat(productList.size()).isEqualTo(2);
}
@DisplayName("JUnit test for get product by id operation")
@Test
public void givenProductObject_whenFindById_thenReturnProductObject(){
// given - precondition or setup
Product p1=new Product("laptop",120000);
productRepo.save(p1);
assertThat(updatedProduct.getPrice()).isEqualTo(130000);
}
import com.productapp.repo.Product;
import com.productapp.repo.ProductRepo;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import java.util.Collections;
import java.util.List;
@Mock
private ProductRepo productRepo;
@InjectMocks
private ProductServiceImpl productService;
@BeforeEach
void setUp() {
product=new Product("laptop", 120000);
}
@AfterEach
void tearDown() {
}
}
import com.fasterxml.jackson.databind.ObjectMapper;
import com.productapp.repo.Product;
import com.productapp.service.ProductService;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.ResultActions;
import java.util.ArrayList;
import java.util.List;
@Autowired
private MockMvc mockMvc;
@MockBean
private ProductService productService;
@Autowired
private ObjectMapper objectMapper;
@Test
public void givenProductObject_whenCreateProduct_thenReturnSavedProduct()
throws Exception{
}
// positive scenario - valid employee id
@Test
public void givenProductId_whenGetProductById_thenReturnProductObject() throws
Exception{
// given - precondition or setup
int productId = 1;
Product product=new Product(1,"laptop", 120000);
given(productService.getById(productId)).willReturn(product);
// @Test
public void givenInvalidProductId_whenGetProductById_thenReturnEmpty() throws
Exception{
// given - precondition or setup
int productId = 1;
Product product=new Product(1,"laptop", 120000);
given(productService.getById(productId)).willReturn(null);
@AfterEach
void tearDown() {
}
}
integration testing:
-------------------
import com.fasterxml.jackson.databind.ObjectMapper;
import com.productapp.repo.Product;
import com.productapp.repo.ProductRepo;
import com.productapp.service.ProductService;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import
org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.ResultActions;
import java.util.ArrayList;
import java.util.List;
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@AutoConfigureMockMvc
public class ProductAppIntegrationTest {
@Autowired
private MockMvc mockMvc;
@Autowired
private ProductService productService;
@Autowired
private ProductRepo productRepo;
@Autowired
private ObjectMapper objectMapper;
@BeforeEach
void setup(){
productRepo.deleteAll();
}
@Test
public void givenProductObject_whenCreateProduct_thenReturnSavedProduct()
throws Exception{
// given - precondition or setup
Product product = Product.builder()
.name("watch")
.price(7000)
.build();
@Test
public void givenListOfProducts_whenGetAllProducts_thenReturnProductList()
throws Exception{
// given - precondition or setup
List<Product> listOfProducts = new ArrayList<>();
listOfProducts.add(Product.builder().name("foo").price(7000).build());
listOfProducts.add(Product.builder().name("bar").price(7000).build());
productRepo.saveAll(listOfProducts);
// when - action or the behaviour that we are going test
ResultActions response = mockMvc.perform(get("/products"));