Module 8: Testing & Deployment - Going Live

Writing code is just the beginning. Let's learn how professionals ensure their code works and how they share it with the world.

8.1 Unit Testing with JUnit and Mockito

Unit Testing is the practice of testing the smallest possible piece of your code—a "unit," which is typically a single method—in complete isolation from the rest of the application.

The "Why": The Problem with Isolation

Consider our AccountService. Its `deposit` method depends on the AccountRepository to fetch and save data. How can we test the deposit logic *without* involving a real database? We want to be sure the math in the service is correct, regardless of the database's state. This is where mocking comes in.

The "How": JUnit 5 and Mockito

  • JUnit 5: The standard testing framework for Java. It provides the @Test annotation and assertion methods (e.g., assertEquals) to verify outcomes.
  • Mockito: A "mocking" framework. It allows us to create fake, controllable versions of dependencies (like our AccountRepository). We can tell these "mocks" exactly how to behave during a test.

Example: Testing the `deposit` Method

Let's write a unit test for our `AccountService`. This test will live in the src/test/java directory.


import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.*;

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.Optional;

@ExtendWith(MockitoExtension.class) // Enables Mockito
class AccountServiceTest {

    @Mock // 1. Mockito will create a fake AccountRepository
    private AccountRepository accountRepository;

    @InjectMocks // 2. Creates an AccountService instance and injects the mock repository into it
    private AccountService accountService;

    @Test
    void testDeposit_Success() {
        // --- 1. Arrange (Setup) ---
        long accountId = 1L;
        double initialBalance = 1000.0;
        double depositAmount = 500.0;
        
        Account mockAccount = new Account(); // A test account object
        mockAccount.setId(accountId);
        mockAccount.setBalance(initialBalance);
        
        // Tell the mock repository what to do:
        // "When findById(1L) is called, then return our mockAccount"
        when(accountRepository.findById(accountId)).thenReturn(Optional.of(mockAccount));
        
        // --- 2. Act (Execute) ---
        Account updatedAccount = accountService.deposit(accountId, depositAmount);
        
        // --- 3. Assert (Verify) ---
        // Check that the balance is correct
        assertEquals(initialBalance + depositAmount, updatedAccount.getBalance());
        
        // Verify that the repository's save method was called exactly once
        verify(accountRepository, times(1)).save(mockAccount);
    }
}

8.2 Postman Testing for APIs

While unit tests are for testing code in isolation, we still need to test the whole system working together. This is where we use Postman for end-to-end API testing. By creating a "Collection" of requests in Postman for all our banking endpoints, we can quickly verify that our entire application—from the controller receiving the request to the data being saved in the database—is functioning correctly after any code changes.

8.3 Packaging Your Spring Boot App (JAR vs. WAR)

Before we can deploy our application, we need to package it into a distributable format.

  • JAR (Java Archive): This is the default and recommended format for Spring Boot. A JAR file is a self-contained, executable application. It includes all your code, dependencies, AND an embedded web server (Tomcat). It's incredibly simple to run.
  • WAR (Web Archive): This is a more traditional format that contains only your application code. It's designed to be deployed into a separate, standalone application server like an external Tomcat or JBoss.

To build your application, you run a simple Maven command from your project's root directory:


mvn clean package

This command will compile your code, run your tests, and create a .jar file inside a new /target directory.

8.4 & 8.5 Running and Deploying to the Cloud

Once you have your JAR file, running your application locally is trivial:


java -jar target/your-app-name-0.0.1-SNAPSHOT.jar

But how do we get it on the internet? We deploy it to a cloud platform. For beginners, the easiest platform to start with is Heroku, a Platform as a Service (PaaS).

Heroku abstracts away the complexity of managing servers. You simply provide your code, and Heroku handles the rest—compiling, deploying, and running it on a public URL.

Basic Steps to Deploy on Heroku

  1. Sign up for a free account at heroku.com and install the Heroku CLI.
  2. Initialize Git: Make sure your project is a Git repository (`git init`, `git add .`, `git commit -m "Initial commit"`).
  3. Create a `Procfile`: In your project's root directory, create a file named Procfile (no extension) with this single line. This tells Heroku how to run your app.
    
    web: java -jar target/your-app-name-0.0.1-SNAPSHOT.jar
    
  4. Create a Heroku App: From your terminal, run heroku login and then:
    
    heroku create your-unique-app-name
    
  5. Deploy: Push your code to Heroku's remote Git repository.
    
    git push heroku main
    

Heroku will then build and deploy your application. In a few minutes, you can visit `your-unique-app-name.herokuapp.com` and interact with your live application!