- Lab
-
Libraries: If you want this lab, consider one of these libraries.
- Core Tech
Guided: Secure and Test an Auction Application with Spring Framework 6
In this compact yet comprehensive Code Lab, we'll journey into the realms of application security and testing with the cutting-edge Spring Framework 6. Our hands-on project will revolve around an auction application, which we'll secure and test. You'll gain practical proficiency in integrating Spring Security for managing authentication and authorization, You'll gain tangible experience in testing Spring 6 applications using tools like JUnit and Hamcrest, equipping you to write and execute a range of tests from unit and integration to end-to-end to ensure optimal functionality.
Lab Info
Table of Contents
-
Challenge
Item Class Testing
In this module, you will be learning how to write a simple JUnit test for the
Itemclass. JUnit is a popular testing framework for Java, and it's an essential tool for any Java developer. The goal of this module is to help you understand how to create tests that validate the behavior of your code.Relevant File: src/test/java/com/pluralsight/auction/ItemTest.java
Task 1: Define Test Variables
Let's start with defining some data that we'll use for testing. In the
testItemmethod, create the following variables:itemName: a String representing the name of the item. Set it to "testItem".itemDescription: a String representing the item's description. Set it to "testDescription".itemSeller: a String representing the seller's name. Set it to "testSeller".itemPrice: a double representing the item's price. Set it to 100.0.itemReserve: a double representing the item's reserve price. Set it to 50.0.
The purpose of these variables is to act as "test data". We will use them to create an instance of
Itemand check if the item's properties match these values.Task 2: Instantiate the Item
Now that you have your test data, let's create an instance of
Item. In thetestItemmethod, instantiate anItemwith the variables you defined in Task 1.Remember, the constructor of the
Itemclass should look something like this:Item(String name, String description, String seller, double price, double reserve).
Use the variables you defined earlier as arguments when creating the
Item.This
Iteminstance will be the "system under test". It's the object that we're going to test in this module.Task 3: Assert the Item's Properties
The final part is to validate that the
Item's properties match the values we passed to it. We do this with assertions.In the
testItemmethod, write fiveassertEqualsstatements to verify that:- The item's name matches
itemName. - The item's description matches
itemDescription. - The item's seller matches
itemSeller. - The item's price matches
itemPrice. - The item's reserve matches
itemReserve.
Remember,
assertEqualstakes two arguments: the expected value and the actual value. The expected value should be the test data, and the actual value should be the corresponding property of theItem.Important Note: Make sure to not mix up the order of the arguments in
assertEquals. The first argument is the expected value (your test data), and the second argument is the actual value (theItemproperty). Mixing up these arguments won't cause your test to fail, but it can make the error messages confusing if a test does fail.After you complete these tasks, you should have a working JUnit test for the
Itemclass. This test validates that theItem's properties are correctly set during instantiation.To run the tests type the comand
gradle testin the terminal The solution can be found in thesolutionfolder. -
Challenge
Item Repository Testing
In this module, you'll delve into data persistence testing using Spring's
DataJpaTestannotation. You'll be testing theItemRepository, which is an interface for generic CRUD operations on ourItementity.Relevant File: src/test/java/com/pluralsight/auction/ItemRepositoryTest.java
Task 1: Create a Test Item
First, you need to create an instance of
Itemthat will be used for testing. Within thetestSaveAndFindmethod, instantiate anItemwith the following parameters:- Name: "testItem"
- Description: "testDescription"
- Seller: "testSeller"
- Price: 100.0
- Reserve: 50.0
This
Iteminstance will be the "system under test". It's the object that we're going to persist and retrieve from the database.Task 2: Save the Test Item
Now, let's persist the
Iteminstance you created in the previous task. Use thesavemethod of theItemRepositoryto save theIteminstance to the database.Remember to assign the result of the
savemethod back to theitemvariable. This is because thesavemethod returns a new instance that represents the persisted state (including the generated ID).Task 3: Retrieve the Test Item
After persisting the
Iteminstance, you'll want to retrieve it to ensure it was saved correctly.Use the
findByIdmethod of theItemRepositoryto retrieve theItemfrom the database. The argument should be the ID of theitemyou just saved.Remember,
findByIdreturns anOptional<Item>, so you'll need to handle the possibility that the item might not be found.Task 4: Assert the Retrieved Item
The final part of this task is to validate that the item retrieved from the database matches the item you saved.
First, assert that the
Optional<Item>is not empty using theassertTruemethod and theisPresentmethod ofOptional. This ensures that an item was actually returned from the database.Next, assert that the name of the retrieved item matches the name of the item you saved. Use the
getmethod ofOptionalto retrieve theItemand thegetNamemethod ofItemto get its name. Then, useassertEqualsto compare it to the name of the item you saved.Important Note: Be cautious when using the
getmethod ofOptional. It throws aNoSuchElementExceptionif theOptionalis empty. In this case, it's safe to use because you've already checked that theOptionalis not empty.After completing these tasks, you should have a working test that validates the basic functionality of the
ItemRepository. This test ensures that anItemcan be successfully saved and retrieved from the database.To run the tests type the comand
gradle testin the terminal The solution can be found in thesolutionfolder. -
Challenge
Item Controller Testing
In this module, you'll be testing the
ItemControllerclass, which is responsible for handling HTTP requests related toIteminstances. TheMockMvcclass will be used to perform HTTP requests, and theItemRepositorywill be mocked using Mockito.Relevant File: src/test/java/com/pluralsight/auction/ItemControllerTest.java
Task 1: Create a Test Item and Configure Mock Behavior
First, create a test
Iteminstance within thetestListItemsmethod, similar to what you've done in previous modules.Next, define a
List<Item>containing the test item. This list will represent the items in the repository.Then, configure the mock
ItemRepositoryto return this list when itsfindAllmethod is called. Mockito'swhenmethod lets you define what should be returned when a certain method is called on a mock object.Task 2: Perform Request and Assert Model
Now, use
MockMvcto perform a GET request to the root URL ("/").Use the
andExpectmethod to validate the response. You should check the following:- The HTTP status is OK.
- The view name is "index".
- The model contains an attribute named "items".
- The "items" attribute equals the list of items you defined earlier.
The
status,view, andmodelmethods are static imports fromMockMvcResultMatchers. They returnResultMatcherinstances that can be used to verify different aspects of the HTTP response.Task 3: Perform Request and Assert View
Create another test method,
testListItemsView, to validate the content of the view.Set up the test item, the list of items, and the mock behavior exactly like in the previous task.
Use
MockMvcto perform a GET request to the root URL ("/") again.This time, check the following in addition to the HTTP status and view name:
- The response content contains the string "Auction Items".
- The response content contains the name, description, seller, and price of the test item.
The
contentmethod is another static import fromMockMvcResultMatchers. It returnsResultMatcherinstances that verify the content of the HTTP response.After completing these tasks, you should have two working tests for the
ItemController.testListItemschecks that the model contains the correct items, whiletestListItemsViewensures that these items are correctly displayed in the view.To run the tests type the comand
gradle testin the terminal The solution can be found in thesolutionfolder. -
Challenge
Spring Security Configuration
In this module, you'll be setting up Spring Security to secure your application. You'll configure HTTP security, password encoding, and user details service.
Relevant File: src/main/java/com/pluralsight/auction/SecurityConfig.java
Task 1: HTTP Security Configuration
First, define a
SecurityFilterChainbean to set up HTTP security. In thefilterChainmethod, build aHttpSecurityinstance that defines which requests should be authorized and how users should authenticate themselves.Disable CSRF protection for simplicity, as it's not the focus of this module.
Permit all requests to static resources and the root URL ("/"). Requests to the "/admin" URL will require the user to have the "ADMIN" role.
Configure form-based login and logout. The login page URL, login processing URL, and default success URL will be "/login", "/login", and "/admin", respectively. You'll also permit all requests to these URLs.
The logout request matcher will be a new
AntPathRequestMatcherfor the "/logout" URL. All requests to this URL will also be permitted.Finally, build the
HttpSecurityinstance and return it.Task 2: Password Encoder Configuration
Next, define a
PasswordEncoderbean. ThepasswordEncodermethod will return a newBCryptPasswordEncoderinstance.The
BCryptPasswordEncoderuses the BCrypt hashing algorithm to encode passwords. It's a good choice for password encoding because it's computationally expensive, which makes it difficult for attackers to crack the hashed passwords.Task 3: User Details Service Configuration
The last task is to define a
UserDetailsServicebean. This service is responsible for loading user-specific data during authentication.In the
userDetailsServicemethod, you'll create anUserDetailsinstance for an admin user. The username and password will both be "admin", and the user will have the "ADMIN" role. The password will be encoded using thePasswordEncoderyou defined earlier.Finally, return a new
InMemoryUserDetailsManagerwith the admin user. TheInMemoryUserDetailsManageris a simpleUserDetailsServiceimplementation that stores user details in memory.After completing these tasks, your application will be secured with Spring Security. Users will need to log in to access the "/admin" URL, and their passwords will be securely encoded.
To run view the application in the browser run the comand
gradle bootrunin the terminal. Open the Simple Browser in VS Code by opening the command palette and typingSimple BrowserThe solution can be found in thesolutionfolder. -
Challenge
Admin Controller Testing
In this module, you'll be testing the
AdminControllerclass, which is responsible for handling HTTP requests related to admin operations. TheMockMvcclass will be used to perform HTTP requests, and theItemRepositorywill be mocked using Mockito. The@WithMockUserannotation will be used to simulate a logged-in user.Relevant File: src/test/java/com/pluralsight/auction/AdminControllerTest.java
Task 1: Set Up Test Environment
First, annotate the
AdminControllerTestclass with@SpringBootTestand@AutoConfigureMockMvcto set up a Spring Boot test environment with aMockMvcinstance.Then, define fields for
MockMvcandItemRepositoryand annotate them with@Autowiredand@MockBean, respectively.@Autowiredwill inject theMockMvcinstance, and@MockBeanwill create a mockItemRepositoryinstance.Task 2: Create a Test Item and Configure Mock Behavior
Next, create a test method,
testListItems, to validate the model and view.In the test method, you'll create a test
Iteminstance and aList<Item>containing the test item. This list will represent the items in the repository.Then, configure the mock
ItemRepositoryto return this list when itsfindAllmethod is called. Mockito'swhenmethod lets you define what should be returned when a certain method is called on a mock object.Task 3: Simulate a Logged-In User
Annotate the test method with
@WithMockUserto simulate a logged-in user. The username, password, and role will be "admin", "admin", and "ADMIN", respectively. This means the test will be run as if an admin user is logged in.Task 4: Perform Request and Assert Model
Now, use
MockMvcto perform a GET request to the "/admin" URL.Use the
andExpectmethod to validate the response. You should check the following:- The HTTP status is OK.
- The view name is "admin".
- The model contains an attribute named "items".
- The "items" attribute equals the list of items you defined earlier.
The
status,view, andmodelmethods are static imports fromMockMvcResultMatchers. They returnResultMatcherinstances that can be used to verify different aspects of the HTTP response.After completing these tasks, you should have a working test for the
AdminController. ThetestListItemsmethod checks that the model contains the correct items when an admin user is logged in.To run the tests type the comand
gradle testin the terminal The solution can be found in thesolutionfolder.
About the author
Real skill practice before real-world application
Hands-on Labs are real environments created by industry experts to help you learn. These environments help you gain knowledge and experience, practice without compromising your system, test without risk, destroy without fear, and let you learn from your mistakes. Hands-on Labs: practice your skills before delivering in the real world.
Learn by doing
Engage hands-on with the tools and technologies you’re learning. You pick the skill, we provide the credentials and environment.
Follow your guide
All labs have detailed instructions and objectives, guiding you through the learning process and ensuring you understand every step.
Turn time into mastery
On average, you retain 75% more of your learning if you take time to practice. Hands-on labs set you up for success to make those skills stick.