FUNDAMENTALS OF JUNIT TESTING

Lesson 306.1 - FUNDAMENTALS OF JUNIT5 TESTING

Fundamentals Of JUnit5 Testing

Learning Objectives:

This lesson will provide comprehensive reference documentation for programmers who write software tests; extension authors who write test cases; and engine authors who build tools and IDE vendors.

By the end of this lesson, learners will be able to:

  • Describe Monoliths.

  • Define the Test-Driven Development and Test LifeCycle.

  • Describe the JUnit5 and its modules, and the different components that make JUnit5.

  • Write JUnit5 Test Cases.

  • Run/Execute JUnit Tests.

  • Describe Annotations and Assertions.

Table of Contents

  • Shortcomings of Monoliths.

  • Converting From Monolith to Polylith.

  • Positive and Negative Testing.

  • Positive Testing a Polylith.

  • Negative Testing a Polylith.

  • Test-Driven Development (TDD) Methodology.

  • JUnit5.

JUnit5 Components and APIs.

  • Writing Tests.

  • APIs.

Assertions, Lifecycles, and Execution Control

  • Running Tests.

  • Extension Model.

Shortcomings of Monoliths

A monolithic application is typically an application system in which all of the relevant modules are packaged together as a single deployable unit of execution. For example, it might be a Java Web Application (WAR) running on Tomcat. However, monoliths do have shortcomings:

Monolithic structures can only be tested by running the entire application.

  • Monolithic structures do not support testing of individual behaviors.

  • Monolithic structures often add implementation without adding behavior.

  • Behaviors are independently testable units of code.

  • Test-Driven Development (TDD) ensures behaviors are established prior to implementation, thus enforcing the existence of a behavior.

Example - Untestable Monolith

The program below can only be tested manually by a user of the application, and does not allow for the creation of automated tests for different inputs.

Converting From Monolith to Polylith

Part 1: We begin by first decoupling the behaviors of the application. Here, we abstract validation logic to separate the method, which allows us to later call the method in a test to ensure our validation algorithm works independently of the entire application.

Polylith is a software architecture that applies functional thinking at the system scale. It helps us build simple, maintainable, testable, and scalable backend systems.

Converting From Monolith to Polylith (continued)

Part 2: In the code below, we replace our tightly-coupled validation logic with a method call to our 'isValid' method.

Positive and Negative Testing

There are two main testing strategies in software: 1) Positive, and 2) Negative:

  • Positive testing determines if your application works as expected.

  • Negative testing ensures that your application can gracefully handle invalid input or unexpected user behavior.

Positive Testing a Polylith

With positive testing a Polylith, we ensure that our application returns "true" upon invoking 'isValid' with a 'String' whose value contains no special-characters.

Negative Testing a Polylith

With Negative Testing a Polylith, we ensure that our application returns Fals` upon invoking 'isValid' with a 'String' whose value contains special-characters.

What is Test Driven Development (TDD)?

Test Driven Development (TDD) is software development approach in which test cases are developed to specify and validate what the code will do. In simple terms, test cases for each functionality are created and tested first and if the test fails then the new code is written in order to pass the test and making code simple and bug-free.

  • TDD framework instructs developers to write new code only if an automated test has failed. This avoids duplication of code.

Why TDD?

  • It helps you focus on design

  • "The act of writing a unit test is more an act of design than of verification. It is also more an act of documentation than of verification" (Uncle Bob).

  • It helps you to think from customer requirements.

  • The act of writing a unit test closes a remarkable number of feedback loops.

  • It helps you to build better written and better tested software.

  • It helps you to write more testable code

Test-Driven Development Methodology

Test-Driven Development (TDD) refers to a style of programming in which three activities are tightly interwoven: coding, testing (in the form of writing unit tests), and design (in the form of refactoring).

It relies on software requirements being converted to test cases before software is fully developed. TDD It can be succinctly described by the following set of rules:

  • Write a "single" unit test in JAVA describing an aspect or requirement of the program.

  • Run the test, which should fail because the program lacks that specific feature.

  • Write "just enough" code (the simplest possible) to make the test pass.

  • Refactor the code until it conforms to the simplicity criteria.

  • Repeat "accumulating" unit tests over time.

Test-Driven Development Methodology - LifeCycle

Five-Step TDD:

Sequential Approach

Ref : https://en.wikipedia.org/wiki/Test-driven development\#/media/File:TDD Global Lifecycle.png

Test-Driven Development Methodology - Software

Frameworks:

There are many testing frameworks and tools that are useful in TDD. Unit tests are so named because each tests only one unit of code. A complex module may have a thousand unit tests and a simple module may have only few. Unit tests used for TDD should never cross process boundaries in a program. Introducing dependencies on external modules or data also turns unit tests into integration tests.

When it comes to Java applications, Java testing frameworks can help test JAVA/J2EE applications with ease. Some of the advantages of using Java testing frameworks include:

  • The time used to develop robust Java based apps can be greatly reduced.

  • Security issues can be unraveled easily.

  • Due to wide usage (in the millions), support is great.

  • They are very cost-effective.

Overview of Unit Testing

Unit Testing, as the name suggests, is the testing functionality of a unit of software individually. The unit can be a module, class, component, element, individual function, method, or procedure. This type of testing is very useful in detecting errors or bugs, or defects at the beginning of the software development life cycle.

  • Unit testing is a white box testing technique, which means that testing is performed where it is known how the software works internally. However, white box testing alone is not enough.

  • Unit testing decreases or reduces the overall cost of developing and reduces the development time.

  • Two types of unit testing can be done: 1) Manual testing and, 2) Automated testing.

  • Unit tests should be fine-grained and test a single, or small numbers of closely-related methods() and classes().

Example for Unit Testing:

  • Consider a leave management application: development of UI, connecting to the database, retrieving and updating the database could be individual units.

  • Testing of these units after they are developed is an example for Unit Testing.

Visit Wiki the document for more about Unit Testing

Overview of Unit Test (continued)

Who performs it?

Unit testing is generally performed by software developers. Developers can catch errors at a very early stage. The longer you wait to fix a bug, the more expensive it gets to fix it. A bug found during the development takes less time to fix.

  • Test Artifacts created are:

  1. Unit test case documents.

  2. Unit test logs.

  3. Unit test defect report. - Objective of Unit Testing:

  4. To isolate a section of code.

  5. To verify the correctness of the code.

  6. To test every function and procedure.

  7. To fix bugs early in the development cycle and save cost.

  8. To help developers understand the code base and enable them to make changes quickly.

  9. To help with code reuse.

Overview of JUnit Testing

  • The JUnit Platform serves as a foundation for launching testing frameworks on the JVM. It also defines the TestEngine API for developing a testing framework that runs on the platform. Furthermore, the platform provides a Console Launcher to launch the platform from the command line.

  • Junit is a Unit Testing framework.

Built for Java.

Features:

  • Before and After methods.

  • Easily written tests.

  • Graphical output.

  • Easy tracking.

How it works:

  • Annotations

Why we Need JUnit

Why would we use Junit testing in our code?

■ A unit testing framework for Java programming language.

  • JUnit can help you detect and fix errors in your code.

  • JUnit can help you find bugs early in the development phase, which increases the code's reliability.

๖ JUnit can help you improve the quality of your software.

  • JUnit can help you work more efficiently and improve your testing process.

To enable the developer to invest more time in reading the code than writing it.

JUnit Framework

Components:

Precisely JUnit is:

JUnit 5 = JUnit Platform + JUnit Jupiter + JUnit Vintage

  • JUnit Platform serves as the foundation of launching testing frameworks on JVM. It also helps in developing a test framework that can define the TestEngine API. A TestEngine facilitates discovery and execution of tests for a particular programming model.

  • JUnit Jupiter is a combination of programming and extension models that will provide a Test Engine for running Jupiter Java-based tests.

  • JUnit Vintage helps in backward compatibility (JUnit4).

JUnit5 Framework

$\left{\begin{array}{c}\text { Unit Test } \text { Cases }\end{array}\right}$ Building Blocks:

JUnit5 - Features and Comparison

JUnit5: What's New

  • JUnit 5 provides a new extension API

  • Support for the Open Test Reporting format

  • Vintage - provides a TestEngine for running JUnit 4/3; based tests on the platform.

  • Extend - as third party; uses platform for more power and additional functionality.

  • Run tests using Eclipse IDE or others (uses Platform to run).

  • Conditional tests: If you need to run different sets of tests in multiple environments, the conditional tests feature is extremely valuable.

  • Console Launcher - to launch the platform from the command line.

JUnit 4: Pitfalls

  • Old and Obsolete.

  • No new Java features and language features.

■ No new design patterns.

  • One Jar - monolithic application.

Anatomy of a JUnit Test

Define a Test in JUnit

A JUnit test is a method contained in a class, which is only used for testing. This is called a Test class. To define that a certain method is a test method, annotate it with the @Test annotation.

This method executes the code under test. You use an assert method, provided by JUnit or another assert framework, to check an expected result versus the actual result. These method calls are typically called asserts or assert statements.

Assertions Statements

Assertions are utility methods to support asserting conditions in tests.

  • Assertion methods allow you to specify the error message, and the expected and the actual result. An assertion method compares the actual value returned by a test to the expected value.

  • A failed assertion will throw an AssertionFailedError or a subclass of it.

  • JUnit 5 assertions statements help to validate the expected output with the actual output of a test. To keep things simple, all JUnit Jupiter assertions are static methods in the org.junit.jupiter.Assertions class.

Assert Methods

The following table gives an overview of assert methods.

MethodDescription

assertAll()

Assert that all supplied executables do not throw any kind of exception.

assertAll()

Assert that all supplied executables do not throw any kind of exception.

assertArrayEquals()

Assert that all arrays are equal.

assertDoesNotThrow()

Assert that execution of the supplied executable does not throw any kind of exception.

assertEquals()

Assert that expected and actual are equal.

assertNotNull()

Assert that actual is not null.

assertSame()

Assert that expected and actual refer to the same object.

assertTimeout()

Assert that execution of the supplied executable completes before the given timeout is exceeded.

Assert Methods (continued)

MethodDescription

assertArrayEquals()

Assert that all arrays are equal.

assertDoesNotThrow()

Assert that execution of the supplied executable does not throw any kind of exception.

assertEquals()

Assert that expected and actual are equal.

assertfalse()

Assert that the supplied condition if false.

assertlterableEquals()

Assert that expected and actual iterables are deeply equal.

assertlinesMatch()

Assert that expected list of Strings matches actual list.

assertNotEquals()

Assert that expected and actual are not equal.

assertThrows()

$\begin{array}{l}\text { Assert that execution of the supplied executable throws an exception of the expectedType and return the } \ \text { exception. }\end{array}$

JUnit Annotations

The JUnit annotations provide information about test methods, such as:

  • Which methods are going to run before and after test methods; which methods run before and after all of the methods; and which methods or classes will be ignored during the execution.

JUnit supports the following annotations for configuring tests and extending the framework.

AnnotationDescription

@Test

$\begin{array}{l}\text { Denotes that a method is a test method. Unlike JUnit 4's @Test annotation, this annotation does not declare any attributes } \ \text { since test extensions in JUnit Jupiter operate based on their own dedicated annotations. Such methods are inherited } \ \text { unless they are overridden. }\end{array}$

@ParameterizedTest

Denotes that a method is a parameterized test. Such methods are inherited unless they are overridden.

@RepeatedTest

Denotes that a method is a test template for a repeated test. Such methods are inherited unless they are overridden.

@TestFactory

Denotes that a method is a test factory for dynamic tests. Such methods are inherited unless they are overridden. @TestTemplate

JUnit Annotations (continued)

AnnotationDescription

@TestClassOrder

$\begin{array}{l}\text { Used to configure the test class execution order for @Nested test classes in the annotated test class. Such } \ \text { annotations are inherited. }\end{array}$

@TestMethodOrder

$\begin{array}{l}\text { Used to configure the test method execution order for the annotated test class; similar to JUnit 4's } \ \text { @FixMethodOrder. Such annotations are inherited. }\end{array}$

@Testlnstance

Used to configure the test instance lifecycle for the annotated test class. Such annotations are inherited.

@DisplayName

Declares a custom display name for the test class or test method. Such annotations are not inherited.

@DisplayNameGeneration

Declares a custom display name generator for the test class. Such annotations are inherited.

@BeforeEach

$\begin{array}{l}\text { Denotes that the annotated method should be executed before each @Test, @RepeatedTest, and } \ @ \text { ParameterizedTest. }\end{array}$

@AfterEach

$\begin{array}{l}\text { Denotes that the annotated method should be executed after each @Test, @RepeatedTest, and } \ @ \text { @arameterizedTest. }\end{array}$

$@$ @aq

Used to declare tags for filtering tests, either at the class or method level.

JUnit Annotations (continued)

AnnotationDescription

(a)BeforeAll

$\begin{array}{l}\text { Denotes that the annotated method should be executed before all @Test, @RepeatedTest, @ParameterizedTest, and } \ \text { @TestFactory methods in the current class; }\end{array}$

(a) AfterAll

Denotes that the annotated method should be executed after all @Test, @RepeatedTest, and @ParameterizedTest,

@Nested

Denotes that the annotated class is a non-static nested test class.

@Disabled

Used to disable a test class or test method; analogous to JUnit 4's @lgnore.

@Timeout

Used to fail a test, test factory, test template, or lifecycle method if its execution exceeds a given duration.

@ExtendWith

Used to register extensions declaratively. Such annotations are inherited.

@RegisterExtension

Used to register extensions programmatically via fields. Such fields are inherited unless they are shadowed.

@TempDir

$\begin{array}{l}\text { Used to supply a temporary directory via field injection or parameter injection in a lifecycle method or test method; located in } \ \text { the org.junit.jupiter.api.io package. }\end{array}$

Test Classes and Methods

Test methods and lifecycle methods may be declared locally within the current test class, inherited from superclasses, or inherited from interfaces (see Test Interfaces and Default Methods).

  • Test Class: Any top-level class, static member class, or @Nested class that contains at least one test method.

  • Test methods should be public and are always void (any instance method that is directly annotated or meta-annotated with @Test, @RepeatedTest, @ParameterizedTest, @TestFactory, or @TestTemplate).

  • Private methods cannot be called and therefore cannot be tested outside of the class containing the method. However, they can be tested indirectly via a public method (i.e., the public method that calls the private method).

  • Protected methods can be tested by a separate test class as long as it is contained in either the same package as the class being tested or in a package inside another source folder with the same name as the package containing the class being tested. The following slide illustrates this.

  • Lifecycle Method: Any method that is directly annotated or meta-annotated with @BeforeAll, @AfterAll, @BeforeEach, or @AfterEach.

Example - Test Methods

The class JUnitProtected includes a protected method and is tested by the test class JUnitProtectedTest, which is in a different source folder ("src/test/java") but in a package with an identical name as the class being tested ("com.perscholas.junitprotected"). If the package names were different, Eclipse would indicate a visibility/access error.

JUnit - Parameterized Test

  • Parameterized tests allow a developer to run the same test multiple times with different arguments. .._.et's say htat we have_an existing utility function _ and we want to be_confident about its beehavior:

Parameterized tests are like other tests except that we add the @ParameterizedTest annotation:

Project Start - Steps and Pipeline

Writing Java Test Case: Steps

  • Identify unit of requirement to test - Class Instance and Class Method.

๑ Identify input data, if any.

  • Diverse and multiple flavors of input data if any.

๖ Identify multiple test cases.

  • Write Test case(s) in Java.

  • Execute all test cases.

  • Verify results of Actual Value vs. Expected Output.

  • Check Result status - Success or Failure?

  • Provide feedback, loop, and user notification.

Setup - Using Maven Project

New Project Creation:

Step 1: Create a Maven project in IDE.

Step 2: Specify Java Version and Jupiter Version.

  • Step 3: Add the below dependencies:

  • platform

  • api

  • scope

Step 4: Update Maven project.

  • Step 5: Validate folders:

  • src/main/java - Folder has application code

  • src/test/java - Folder has Test cases code I甘I Package Explorer $\times \rightleftarrows \vdots$ ■

JUnit Project - Dependencies and Imports

Project Libraries:

  • Imports to include:

  • Import static org.junit.jupiter.api.Assertions.*;

  • Import org.junit.jupiter.api.Test;

Adding dependencies in pom.xml Jupiter Engine Dependency.

  • Jupiter API Dependency.

  • Jupiter Vintage - old code (optional).

Sample Project - Adding Test Case

Testing Valid Password: Writing Test Cases

Create a Java project that takes a password as input and validates and verifies that it complies with a given set of defined rules. All of the rules are defined in the requirements document, and can serve as a single unit of code (method) that can be tested.

Follow the five-step approach in writing JUnit test cases for each requirement. The initial test will fail since the code is not in-place. Re-factor by writing code, and re-run the test cases. Iteratively, keep writing code until the test passes. Repeat the steps for all of the requirements until all of the test cases pass. Below is the directory structure of the project and test cases in project explorer:

  • Project - junit5.

  • Package - junit.test.

  • Click here: Source Code File - src/main/java/PasswordComply.java.

  • Click here: JUnit Test Case Source File - src/test/java/PasswordComplyTest.java.

  • Click here: src/test/java/PasswordComplyUsingHooksTest.java.

Create Test - Adding Test Case

Create Test Case Using IDE:

  • Adding JUnit Test Case - Identify the unit of code to test in any class (e.g., Click here: PasswordComply).

  • Right-click the Java file and click "New." Then select "JUnit Test Case." src/test/java folder has the java test case file.

Create Test - Adding Test Case

Continued

Create Using IDE:

  • Adding JUnit Test Case:

Version\# to use.

Test Case Source Folder ../src/test/java.

Package Name - same as application.

  • Standard practice.

  • Leverage package visibility.

  • Access to protected Methods

Class Name.

  • $\quad$ same as application with 'Test' appended (Ex: PasswordComplyTest).

  • For Usability and Convention.

Class Under Test.

  • Specify the Application Class to test.

Create Test - Adding Test Case

  • Add Methods to Test.

  • Select all methods to test (list contains all methods from Application).

  • Click Finish.

New JUnit Test Case

Test Methods

Select methods for which test method stubs should be created.

Available methods:

c PasswordComply

Select All

  • doesPasswordComply0

Deselect All

Create Test - Using Classes

  • Add Class directly in:

$\rightarrow \quad \mathrm{src} / \mathrm{test} / \mathrm{java}$

$\rightarrow \quad$ Name the package and class.

$\rightarrow \quad$ Click here: $\rightarrow$ Add annotation "@Test" for each test scenarios (methods).

$\rightarrow$ @Test - JUnit runs those methods

Running Tests - Check Status

  • Executing Test Case Steps:

  • Step\#1 - Junit Runner creates instance of test class.

$\rightarrow$ Click here for code (PasswordComplyTest)

  • Step\#2 - Right-Click on Class.

  • Step\#3 - Run As.

  • Step\#4 - Run Configurations.

Test Results:

  • Success bar (green) and Output to Console.

  • No failure is success.

\$. Problems a Javadoc 9 , Declaration PasswordComplyTe:t (1) [JUnit] G:\Program Files (x86)\sts-4.8 Password conditions success!

O Run all tests in the selected project, package or source folder

Continue...

Running Tests - Fail Check

Test Results:

  • Failure Bar (Red Bar) and Output on Console.

  • Red bar for failures.

  • Shows that all methods ran.

Run All - Identify and Execute Tests

Run All:

  • Step 1 - Right-click on Project

  • Step 2 - Select "Run As."

  • Step 3 - Select "JUnit Test."

  • Execution - what happens?

Scan all classes.

Click here $\rightarrow$ Looks for @Test annotation.

Runs them all.

API - Reporting Assert Results

Continued

Assert: is a method useful in determining Pass or Fail status of a test case. There are various types of assertions (e.g., Boolean, Null, Identical).

Click here $\rightarrow$ assertEquals - compares expected vs. actual results

  • expected (true) equals actual (true).

  • Green bar is displayed.

expected (false) does not equal actual (true).

  • Red bar is displayed.

continue...

API - Assert Messaging

Click here for code $\rightarrow$ assertEquals(expected,actual, String $m s g$ ).

msg - Output reason for failure with message for code readability, debugging, and future use.

API - Assumption

Click here for code $\rightarrow$ assumeTrue(myFileReader != null)

  • Validates the assumption inside, and aborts if not true.

SureFire Plugin - Maven Command Line

Click here $\rightarrow$ Surefire: Plugin is used during the test phase of the build lifecycle to execute the unit tests of an application.

  • Run Junit tests using Maven commands.

Click here $\rightarrow$ Used for $\mathrm{Cl} / \mathrm{CD}$ pipeline during build process.

  • Results:

Assert - Handle Exception

Click here $\rightarrow$ assertThrows(expected, lambda, String $\boldsymbol{m s g}$ )

  • Outputs reason for failure with message for code readability, debugging, and future use.

Assert - Test Results

Click here $\rightarrow$ assertThrows(expected, lambda, String msg)

Expected SQL Exception and received in the test case.

Received SQL Exception but was expecting NullPointerException received in the test case.

JUnit - Example Code \#1: Test Password Complies

Password is valid and returns "true" if ALL below conditions are satisfied:

  • Length is greater or equal to 8 .

  • Length is less than or equal to 12.

  • Has Alphanumeric characters.

  • Has at least one special character.

  • Does not already exist.

  • Not already in use.

  • Does not have have "NOT ALLOWED" characters.

JUnit - Steps to Execute and Validate Tests

  • Step 1 - Create instance of the class (or method's class) to test.

  • Step 2 - Prepare input data.

  • Step 3 - Run the code that needs testing.

  • Step 4 - Verify and validate the results.

  • Step 5 - Compare Expected vs. Actual result set.

JUnit - Test Lifecycle

  • Lifecycle defines what code needs to initialized, run, and ordered.

  • Lifecycle helps code to be run before/after.

  • Multiple test methods should run independently.

  • JUnit5 creates new test instances for every test method.

  • Each method has its own state and creates new instances of test class.

  • Lifecycle "Hooks" are used to run code that is needed:

  • Initialization before running any method: @BeforeAll.

  • Before beginning of each method : @BeforeEach.

  • After end of each method: @AfterEach.

  • End of all methods: @AfterAll.

Hooks - Test Life Cycle Methods

Tests - Read passwords from the file and validate if they comply.

Click here for the code

$\rightarrow$ (PasswordComplyUsingHooksTest.java)

Used during Load Tests for largescale applications when validating all $D B$ resources.

Hooks - Test Lifecycle Methods

Hooks - Test Lifecycle Methods

  • Output:

Hooks - Multiple Nested Runs

Click here for code $\rightarrow$ Read ALL Config File:

Nested allows individual component testing.

Ensure all config entries are valid before starting application servers.

Tags - Allows Separation

Click here for the code $\rightarrow$ Run Tag Based Test.

  • Click here for the code $\rightarrow$ Run only Configuration Tests.

$\times$

All Config entries valid..

Clean Up of all local resources...

All Config entries valid. .

Clean Up of all local resources..

All Config entries valid.

Clean Up of all local resources.

All Config files created...

Clean Up of all local resources.

Clean up of Application Level DB data, Logs, resources etc.. done.

Click here for code $\rightarrow$ Run only DB tests

(2)Tag("DB-Password-Checks")

@DisplayName("Check ALL DB Password are Valid...")

void testDoesPasswordComply() {

assumeTrue( (myFileReader ! null));

哥 PasswordComplyUsingHooksTest [Runner: JUnit 5] (0.010 s) 䌻 Check ALL DB Password are Valid... $\checkmark$ Include Tags

Newline separated tags to be included in the test run: DB-Password-Checks

Logs - Testlnfo and TestReporter

Click here for code $\rightarrow$ TestInfo - Contains information about tests.

Click here for code $\rightarrow$ TestReporter - access to logs and adds messages for reporting.

  • Output :

TestIdentifier [repetition 1 of 2 ]

ReportEntry [timestamp $=$ 2022-09-21T14:57:19.822159200, value = 'Running repetition 1 of 2 under tags [Configuration-File-Check]'] All Config entries valid...

Clean Up of all local resources...

Testidentifier [repetition 2 of 2]

ReportEntry [timestamp $=$ 2022-09-21T14:57:19.827158200, value = 'Running repetition 2 of 2 under tags [Configuration-File-Check]']

All Config entries valid...

Clean Up of all local resources...

TestIdentifier [Config]

ReportEntry [timestamp $=$ 2022-09-21T14:57:19.829157400, value $=$ 'Running Config under tags [Configuration-File-Check]']

All Config files created...

Clean Up of all local resources..

Clean up of Application Level DB data, Logs, resources etc.. done.

Hands-On Lab

Find the GLAB - 306.1.1 - JUnit (Test Driven Development) on Canvas under the Assignment section.

If you have technical questions while performing the lab activity, ask your instructors for assistance.

Test Automation - Design Patterns

  • Page Object Model (Pattern) - pages in the app that are represented as Classes, and various UI elements of that pages are defined as Variables.

  • Factory Design Pattern - have a super class with multiple subclasses, and based on some input, we need to return a particular subclass.

  • Facade Pattern - a facade class, which has methods that combine actions executed on different pages.

Builder Pattern - constructs complex objects with different types and representations.

  • Singleton Pattern - uses the same object across the entire framework.

Dependency Diagram - Correlation

Click here for the code $\rightarrow$ JUnit/Jupiter/Vintage/APIs: Shows dependency on each class.

Combining JDBC with JUnit

Querying Expected Data

  • Why query for expected data?

  • We are not testing the database; just the DAO methods.

What's the process? - @BeforeAll - Set up - @BeforeEach - Query data $>@$ @est - @AfterEach - Reset query - @AfterAll - Close

Querying Expected Data

Testing and Clean-Up

The Process

@AfterAll - Close Connection

Knowledge Check

  • What is JUnit?

  • What is Test-Driven Development?

  • What are the components of JUnit5?

  • What are different assert statements used?

  • What annotations are used to run tests before and after any test?

  • Which annotation is used to run before a test?

  • Which annotation is used to run after a test?

  • What patterns are used in test lifecycle management?

Summary

  • "Test-driven Development" refers to a style of programming where tests are written before code.

  • JUnit is used for launching test frameworks on JVM.

  • JUnit5 is the newer version of JUnit used for latest version of Java code.

  • Green/Red bars denote the results of the tests.

  • Code re-factor is required to pass all of the tests.

  • JUnit Jupiter supports annotations for configuring tests and extending the framework.

  • Lifecycle Method - any method that is directly annotated or meta-annotated with @BeforeAll, @AfterAll, @BeforeEach, or @AfterEach.

  • Test Class - any top-level class, static member class, or @Nested class that contains at least one test method (e.g., a container). Test classes must not be abstract and must have a single constructor.

  • Test Method - any instance method that is directly annotated or meta-annotated with @Test, @RepeatedTest, @ParameterizedTest, @TestFactory, or @TestTemplate.

Additional Reading

Topics:

  • Conditional Test Execution.

  • Method Order.

  • Repeated Tests.

  • Parameterized Tests.

  • Test Templates.

  • Dynamic Tests.

  • Parallel Execution.

  • Built-In Extensions.

Appendix

The following slide topics are referenced in the previous slides.

Code - pom.xml

-ө.0.xsd">

4.0.0

〈groupId〉com. perscholas.javacasestudy</groupId〉

$<$ artifactId - junit5 $5<$ artifactId -

$<$ version>日. 0.1 -SNAPSHOT</version

junit5

〈properties〉

〈maven. compiler. target>11</maven. compiler.target〉

〈maven. compiler. source>11</maven. compiler. source〉

<junit. jupiter. version>5.4.0</junit. jupiter. version>

$</$ properties

〈dependencies〉 〈dependency>

〈groupId>mysql

〈artifactId>mysql-connector-java</artifactId〉

8.0.25

$</$ dependency

org.junit.jupiter

〈artifactId〉junit-jupiter-engine</artifactId〉

<version $>{$ junit.jupiter. version $}</$ version>

scope>test $</$ scope

$\langle/$ dependency $\rangle$

〈groupId>org.junit.jupiter</groupId〉

<artifactId $\rangle$ junit-jupiter-api</artifactId〉

\${junit. jupiter. version $}</$ version〉

test $</$ scope

〈artifactId>maven-surefire-plugin</artifactId〉

〈version>2.22.1</version〉

$</$ plugin $\rangle$

$\langle/$ plugins $\rangle$ 〈build $\rangle\langle/$ project $\rangle$

Code - PasswordComply.java

Code - PasswordComply.java

Code - PasswordComplyTest.java

Code - PasswordComplyUsingHooksTest.java

Code - PasswordComplyUsingHooksTest.java

Code - PasswordComplyUsingHooksTest.java

Last updated