Author

Author- Ram Ranjeet Kumar
Showing posts sorted by relevance for query junit. Sort by date Show all posts
Showing posts sorted by relevance for query junit. Sort by date Show all posts

Saturday, July 29, 2023

JUnit| Unit Testing

Unit testing 

  • Unit testing is a software testing method by which individual units or components of an application are tested to determine whether they are fit for use. 
  • A unit is the smallest testable part of an application, usually a function or method. 
  • Unit testing is done during the development phase by the developers. 
  • The purpose of unit testing is to validate that each unit of the software code performs as expected.

What are the benefits of unit testing?
The benefits of unit testing are:
  • Unit tests help to fix bugs early in the development cycle and save costs.
  • It helps the developers to understand the testing code base and enables them to make changes quickly.
  • Good unit tests serve as project documentation.
  • Unit tests help with code re-use.
  • Migrate both your code and your tests to your new project. Improve the code until the tests run again.

How do I write a good unit test?
  • To write good unit tests, you will need to separate your code properly. 
  • Following the SOLID principle will help a lot. 
  • Separating your project into different layers by using something like multitier architecture can also make it easier to test your application. 
  • Here are some tips for writing great unit tests:
    • Make each test orthogonal (i.e., independent) to all the others.
    • Use the AAA pattern (Arrange, Act, Assert) for each test.
    • Use descriptive names for your tests.
    • Use assertions that are easy to read and understand.
    • Use mocks and stubs when necessary.
    • Test edge cases and boundary conditions.
    • Test error conditions.
    • Test performance and scalability.
    • Test concurrency and threading issues.
    • Test security issues.

What is Junit?
  • JUnit is an open-source framework for writing and running tests in the Java programming language. 
  • It provides annotations, assertions, and methods for testing expected results and repeatable tests. 
  • It is useful for Java Developers and for test-driven development and regression testing.
  • JUnit was created by Kent Beck, Erich Gamma, David Saff, and Kris Vasudevan.

JUnit versions
Here are some details of different JUnit versions:
  1. JUnit 1.x: The first version of JUnit was released in 1997. It was a simple framework that provided only a few annotations and assertions.
  2. JUnit 2.x: This version added more features, such as the ability to test exceptions and timeouts.
  3. JUnit 3.x: This version introduced the TestRunner class, which made it easier to run tests. It also added support for setUp() and tearDown() methods.
  4. JUnit 4.x: This version introduced annotations, which made it easier to write tests. It also added support for parameterized tests and test suites.
  5. JUnit 5.x: This version introduced several new features, such as support for Java 8 lambdas and annotations, dynamic tests, and test interfaces.

What are the differences between JUnit 4 and JUnit 5?
JUnit 5 introduced several new features that are not available in JUnit 4. 
Some of the differences between JUnit 4 and JUnit 5 are:
  • JUnit 5 supports Java 8 lambdas and annotations.
  • JUnit 5 introduced several new annotations, such as @DisplayName and @Nested.
  • JUnit 5 introduced dynamic tests, which allow you to generate tests at runtime.
  • JUnit 5 introduced test interfaces, which allow you to define common test methods in an interface.


What are the advantages of using JUnit 5 over Junit 4?

JUnit 5 introduced several new features that are not available in JUnit 4. Some of the advantages of using JUnit 5 over JUnit 4 are:

  • Better support for Java 8 and above.
  • Improved test organization and readability.
  • More powerful assertions.
  • Better support for parameterized tests.
  • Better support for dynamic tests

How do I install and use JUnit 5 in my project?

To install and use JUnit 5 in your project, follow these steps:
  • Step 1: Set up your project
    • Create a new Java project in your preferred Integrated Development Environment (IDE) like Eclipse, IntelliJ, or NetBeans. Alternatively, you can use a build tool like Maven or Gradle for managing your project dependencies.
    • Ensure that your project is using Java 8 or higher, as JUnit 5 requires Java 8 or later to run.
  • Step 2: Add JUnit 5 dependencies
    • If you are using a build tool like Maven, add the following dependencies to your pom.xml file:
<dependencies>
    <!-- JUnit 5 Jupiter API -->
<!-- https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter-api -->
<dependency>
    <groupId>org.junit.jupiter</groupId>
    <artifactId>junit-jupiter-api</artifactId>
    <version>5.10.0</version>
    <scope>test</scope>
</dependency>

    <!-- JUnit 5 Jupiter Engine (for running tests) -->
   <!-- https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter-engine -->
<dependency>
    <groupId>org.junit.jupiter</groupId>
    <artifactId>junit-jupiter-engine</artifactId>
    <version>5.10.0</version>
    <scope>test</scope>
</dependency>

</dependencies>

    •  If you are using Gradle, add the following dependencies to your build.gradle file:
dependencies {
    // JUnit 5 Jupiter API
    testImplementation 'org.junit.jupiter:junit-jupiter-api:5.7.2'
    // JUnit 5 Jupiter Engine (for running tests)
    testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.7.2'
}


  • Step 3: Write and run JUnit 5 tests
    • Create a test class in your project. The test class should use JUnit 5 annotations for defining test methods.

Sunday, July 30, 2023

Junit Assertions




Assertion in Junit

In JUnit, assertions are used to verify the expected behavior of your code during testing. They allow you to check if certain conditions are true or false and report the test results accordingly. If an assertion fails, the test is considered to have failed.

JUnit provides a set of static methods in the Assertions class (JUnit 5) or Assert class (JUnit 4) for making assertions. Here are some common assertion methods:
  • assertEquals(expected, actual): This assertion checks if the expected value is equal to the actual value.
import org.junit.jupiter.api.Assertions;
@Test
public void testAddition() {
    int result = add(3, 5);
    Assertions.assertEquals(8, result);
}

  • assertTrue(condition): This assertion checks if the given condition is true.
import org.junit.jupiter.api.Assertions;
@Test
public void testIsPositive() {
    int number = 10;
    Assertions.assertTrue(number > 0);
}

  • assertFalse(condition): This assertion checks if the given condition is false.
import org.junit.jupiter.api.Assertions;
@Test
public void testIsNegative() {
    int number = -5;
    Assertions.assertFalse(number > 0);
}

  • assertNull(object): This assertion checks if the given object is null.
import org.junit.jupiter.api.Assertions;
@Test
public void testIsNull() {
    Object obj = null;
    Assertions.assertNull(obj);
}

  • assertNotNull(object): This assertion checks if the given object is not null.
import org.junit.jupiter.api.Assertions;
@Test
public void testIsNotNull() {
    Object obj = new Object();
    Assertions.assertNotNull(obj);
}

  • assertSame(expected, actual): This assertion checks if the expected and actual references point to the same object.
import org.junit.jupiter.api.Assertions;
@Test
public void testSameReference() {
    Object obj1 = new Object();
    Object obj2 = obj1;
    Assertions.assertSame(obj1, obj2);
}

  • assertNotSame(expected, actual): This assertion checks if the expected and actual references do not point to the same object.
import org.junit.jupiter.api.Assertions;
@Test
public void testDifferentReferences() {
    Object obj1 = new Object();
    Object obj2 = new Object();
    Assertions.assertNotSame(obj1, obj2);
}

  • assertThrows(exceptionType, executable): This assertion checks if the executable throws an exception of the specified exceptionType.
import org.junit.jupiter.api.Assertions;
@Test
public void testDivideByZero() {
    int a = 10;
    int b = 0;
    Assertions.assertThrows(ArithmeticException.class, () -> divide(a, b));
}


These are some of the commonly used assertion methods in JUnit. Depending on the version of JUnit you are using (JUnit 5 or JUnit 4), the assertion methods may have slight differences in naming and package import. Always make sure to import the appropriate assertion class based on your JUnit version.

Tuesday, August 15, 2023

Write Junit Test case for a Java class with all functionality



To use JUnit in your Maven project, you need to add the JUnit dependency to your pom.xml file. Additionally, if you're using JUnit 5 (JUnit Jupiter), you'll also need to include the JUnit Jupiter API and the JUnit Jupiter Engine dependencies. Here's how you can do it:

<dependencies>

    <!-- JUnit 5 -->

    <dependency>

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

        <artifactId>junit-jupiter-api</artifactId>

        <version>5.8.1</version>

        <scope>test</scope>

    </dependency>

    <dependency>

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

        <artifactId>junit-jupiter-engine</artifactId>

        <version>5.8.1</version>

        <scope>test</scope>

    </dependency>

</dependencies>


 Here's the Calculator class

public class Calculator {


    public int add(int a, int b) {

        return a + b;

    }


    public int subtract(int a, int b) {

        return a - b;

    }


    public int multiply(int a, int b) {

        return a * b;

    }


    public double divide(int a, int b) {

        if (b == 0) {

            throw new ArithmeticException("Cannot divide by zero");

        }

        return (double) a / b;

    }

}


This is the Calculator class that performs basic arithmetic operations. Make sure both the Calculator class and the JUnit test class are in the same package or properly imported for the test cases to work as intended.

Here's how you can write JUnit test cases to test its functionality:

import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;

public class CalculatorTest {

    @Test
    public void testAddition() {
        Calculator calculator = new Calculator();
        int result = calculator.add(5, 7);
        assertEquals(12, result);
    }

    @Test
    public void testSubtraction() {
        Calculator calculator = new Calculator();
        int result = calculator.subtract(10, 3);
        assertEquals(7, result);
    }

    @Test
    public void testMultiplication() {
        Calculator calculator = new Calculator();
        int result = calculator.multiply(4, 6);
        assertEquals(24, result);
    }

    @Test
    public void testDivision() {
        Calculator calculator = new Calculator();
        double result = calculator.divide(15, 3);
        assertEquals(5.0, result, 0.001); // Using delta for double comparison
    }

    @Test
    public void testDivisionByZero() {
        Calculator calculator = new Calculator();
        assertThrows(ArithmeticException.class, () -> calculator.divide(10, 0));
    }
}


In this example, the Calculator class has methods for addition, subtraction, multiplication, and division. The JUnit test class CalculatorTest contains several test methods:
  • testAddition: Tests the addition method.
  • testSubtraction: Tests the subtraction method.
  • testMultiplication: Tests the multiplication method.
  • testDivision: Tests the division method.
  • testDivisionByZero: Tests whether division by zero throws an ArithmeticException.
Remember to have your Calculator class and JUnit library properly set up in your project for these test cases to work. Additionally, you might need to adjust the code based on your specific project structure and requirements.

Saturday, August 12, 2023

@MethodSource Annotation With @ParameterizedTest in JUnit5



  • The @MethodSource annotation is a part of the JUnit 5 testing framework in Java.
  •  It is used to specify a method as the source of test cases for parameterized tests. 
  • Parameterized tests allow you to run the same test logic with multiple sets of input parameters, making your testing more comprehensive and efficient.
  • The @MethodSource annotation is used to indicate that the source of test cases for a parameterized test method comes from another method. 
  • This annotation is applied to the parameterized test method itself.
  • @MethodSource is an annotation that allows you to provide arguments for a parameterized test from a factory method.
  • The factory method can be in the same class as the test or in an external class. 
  • The factory method must return a stream, iterable, iterator, or array of arguments. 

Example:
Let's say you have a simple class called MathUtils with a method add(int a, int b) that adds two integers

public class MathUtils {
    public static int add(int a, int b) {
        return a + b;
    }
}

Now, you want to write parameterized tests for the add method using JUnit 5 and the @MethodSource annotation.
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
import java.util.stream.Stream;

import static org.junit.jupiter.api.Assertions.assertEquals;

public class MathUtilsTest {

    @ParameterizedTest
    @MethodSource("additionProvider")
    void testAddition(int a, int b, int expectedResult) {
        int result = MathUtils.add(a, b);
        assertEquals(expectedResult, result);
    }

    static Stream<Arguments> additionProvider() {
        return Stream.of(
            Arguments.of(2, 3, 5),
            Arguments.of(-1, 1, 0),
            Arguments.of(0, 0, 0)
        );
    }
}

In this example:
  • The testAddition method is a parameterized test method that takes three parameters: a, b, and expectedResult.
  • The @MethodSource("additionProvider") annotation specifies that the test cases will be provided by the method named additionProvider.
  • The additionProvider method returns a Stream<Arguments> containing sets of arguments for the parameterized test.
  • When you run the tests, JUnit 5 will generate separate test cases for each set of arguments provided by the additionProvider method. 
  • This way, you can easily test the add method with various input values without writing multiple individual test methods.

Let's consider another example using a different data type. Suppose you have a class called StringUtils with a method concatenate(String a, String b) that concatenates two strings

public class StringUtils {
    public static String concatenate(String a, String b) {
        return a + b;
    }
}

Now, you want to write parameterized tests for the concatenate method using JUnit 5 and the @MethodSource annotation.

import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import java.util.stream.Stream;

import static org.junit.jupiter.api.Assertions.assertEquals;

public class StringUtilsTest {

    @ParameterizedTest
    @MethodSource("concatenationProvider")
    void testConcatenation(String a, String b, String expectedResult) {
        String result = StringUtils.concatenate(a, b);
        assertEquals(expectedResult, result);
    }

    static Stream<Arguments> concatenationProvider() {
        return Stream.of(
            Arguments.of("Hello, ", "world!", "Hello, world!"),
            Arguments.of("", "Test", "Test"),
            Arguments.of("Java ", "Programming", "Java Programming")
        );
    }
}


In this example:

  • The testConcatenation method is a parameterized test method that takes three parameters: a, b, and expectedResult.
  • The @MethodSource("concatenationProvider") annotation specifies that the test cases will be provided by the method named concatenationProvider.
  • The concatenationProvider method returns a Stream<Arguments> containing sets of arguments for the parameterized test.
  • When you run the tests, JUnit 5 will generate separate test cases for each set of arguments provided by the concatenationProvider method. This allows you to test the concatenate method with various combinations of strings without writing repetitive test code.

Here is an example of using @MethodSource annotation with an iterable:

@ParameterizedTest
@MethodSource("provideStringsForIsBlank")
void isBlank_ShouldReturnTrueForNullOrBlankStrings(String input, boolean expected) {
    assertEquals(expected, Strings.isBlank(input));
}

static Stream<Arguments> provideStringsForIsBlank() {
    return Stream.of(
      Arguments.of(null, true),
      Arguments.of("", true),
      Arguments.of("  ", true),
      Arguments.of("not blank", false)
    );
}

Here is an example of using @MethodSource annotation with an iterator:

@ParameterizedTest
@MethodSource("provideIntegers")
void testWithIteratorSource(int argument) {
    assertNotEquals(9, argument);
}

static Iterator<Integer> provideIntegers() {
    return Arrays.asList(1, 2, 3, 4, 5).iterator();
}

Here is an example of using @MethodSource annotation with an array:

@ParameterizedTest
@MethodSource("provideStrings")
void testWithArraySource(String argument) {
    assertNotNull(argument);
}

static String[] provideStrings() {
    return new String[] {"hello", "world"};
}

Remember to add the appropriate JUnit 5 dependencies to your project to use these annotations and features.


Sunday, July 30, 2023

Junit5 Annotations


 

JUnit5 annotations

  • @Test: This annotation is similar to the one in JUnit 4 and is used to mark a method as a test method.
@Test
public void testAddition() {
    // Test logic and assertions go here
}


  • @BeforeEach: This annotation is used to mark a method that should be executed before each test method in the class. It is typically used to set up the test environment or initialize resources.
@BeforeEach
public void setUp() {
    // Initialization logic goes here
}
  • @AfterEach: This annotation is used to mark a method that should be executed after each test method in the class. It is typically used to clean up resources or perform cleanup operations.
@AfterEach
public void tearDown() {
    // Cleanup logic goes here
}

  • @BeforeAll: This annotation is used to mark a method that should be executed once before any test methods in the class. It is used for setup that should be performed only once.
@BeforeAll
public static void setUpClass() {
    // One-time setup logic goes here
}

  • @AfterAll: This annotation is used to mark a method that should be executed once after all test methods in the class have been executed. It is used for cleanup that should be performed only once.
@AfterAll
public static void tearDownClass() {
    // One-time cleanup logic goes here
}

  • @RepeatedTest : This annotation is used in JUnit 5 to repeat a test multiple times. The simplest way of using the annotation is to pass an integer value as an argument. Here is an example of how to use the annotation:
@RepeatedTest(5)
public void testRepeatedTest() {
    System.out.println("Hello World");
}
This will run the annotated method 5 times.

@ParameterizedTest:  This annotation is used in JUnit 5 to run the same test multiple times with different arguments. Here is an example of how to use the annotation:

@ParameterizedTest
@ValueSource(strings = { "madam", "java", "racecar" })
void palindromes(String value) {
    assertTrue(StringUtils.isPalindrome(value));
}

This will run the test method three times with the arguments "madam", "java, and "racecar" respectively.

  • @TestFactory: This  annotation is used in JUnit 5 to create dynamic tests. A dynamic test is a test that is generated at runtime by a factory method using the @TestFactory annotation. The method marked @TestFactory is not a test case, rather it’s a factory for test cases. Here is an example of how to use the annotation:
@TestFactory
Stream<DynamicTest> dynamicTestsFromStream() {
    return Stream.of("racecar", "radar", "able was I ere I saw elba")
      .map(text -> DynamicTest.dynamicTest("Palindrome test for " + text, () -> assertTrue(StringUtils.isPalindrome(text))));
}

This will create three dynamic tests with the arguments "racecar", "radar", and "able was I ere I saw elba" respectively.


  • @Disabled: This annotation is used to disable a test method or an entire test class during test execution. It is similar to @Ignore in JUnit 4.
@Disabled
@Test
public void disabledTestMethod() {
    // This test method will be disabled during test execution
}
  • @DisplayName: This annotation is used to provide a custom display name for a test method or a test class. It allows you to give more descriptive names to your tests.
@Test
@DisplayName("Test addition operation")
public void testAddition() {
    // Test logic and assertions go here
}
  • @Nested: This annotation is used to define nested test classes. Nested test classes can access the private fields and methods of the outer class, allowing better test organization.
public class OuterTestClass {

    @Nested
    class InnerTestClass {
        // Test methods and other annotations go here
    }
}

  • @TestClassOrder:  It is used in JUnit 5 to configure a ClassOrderer for the @Nested test classes of the annotated test class. If @TestClassOrder is not explicitly declared on a test class, inherited from a parent class, declared on a test interface implemented by a test class, or inherited from an enclosing class, @Nested test classes will be executed in arbitrary order. As an alternative to @TestClassOrder, a global ClassOrderer can be configured for the entire test suite via the "junit.jupiter.testclass.order.default" configuration parameter¹. 

Here's an example of how to use @TestClassOrder:


@TestClassOrder(ClassOrderer.OrderAnnotation.class)
class OrderedNestedTests {
    @Nested
    @Order(1)
    class PrimaryTests {
        // @Test methods ...
    }

    @Nested
    @Order(2)
    class SecondaryTests {
        // @Test methods ...
    }
}

This will guarantee that @Nested test classes are executed in the order specified via the @Order annotation.


  • @TestMethodOrder:  It is used in JUnit 5 to control the execution order of tests. We can use our own MethodOrderer, as we'll see later. Or we can select one of three built-in orderers:
    • Alphanumeric Order, 
    • @Order Annotation, 
    • Random Order. 

Here's an example of how to use @TestMethodOrder

@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
class OrderedTests {
    @Test
    @Order(1)
    void nullValues() {}

    @Test
    @Order(2)
    void emptyValues() {}

    @Test
    @Order(3)
    void validValues() {}
}

This will guarantee that test methods are executed in the order specified via the @Order annotation




These are some of the essential annotations provided by JUnit 5. JUnit 5 also introduces many other features and improvements, such as parameterized tests, dynamic tests, test interfaces, and more, making it a powerful and modern testing framework for Java developers.

Wednesday, August 16, 2023

Mockito Framework


Introduction
  • Mockito is an open-source testing framework for Java released under the MIT(Massachusetts Institute of Technology)  License. 
  • Mockito is a Java-based mocking framework used for unit testing of Java applications. 
  • Mockito plays a crucial role in developing testable applications.
  • Mockito is a testing technique where mock objects are used instead of real objects for testing purposes. 
  • Mock objects provide a specific (dummy) output for a particular (dummy) input passed to it.

Here's a simple explanation with an example:
Imagine you're building a car. Your car has an engine, and the engine needs to be tested. But, testing the engine might involve other complex parts like the transmission and fuel system. Instead of building an entire car just to test the engine, you could use a mock engine that simulates the real engine's behavior.

In coding terms, Mockito lets you create these "mock" objects to stand in for real components. You can use these mock objects to check if certain interactions between parts of your code are happening correctly.

Let's say you have a class called `Car` that depends on an `Engine` class. You want to test the `Car` class without worrying about the `Engine` class's actual behavior. Here's how you could do it with Mockito:

import static org.mockito.Mockito.*;
// Imagine you have these classes
class Engine {
    public String start() {
        return "Vroom!";
    }
}

class Car {
    private Engine engine;

    public Car(Engine engine) {
        this.engine = engine;
    }

    public String startCar() {
        return engine.start();
    }
}

public class Main {
    public static void main(String[] args) {
        // Create a mock engine
        Engine mockEngine = mock(Engine.class);

        // Set up the mock's behavior
        when(mockEngine.start()).thenReturn("Mock Vroom!");

        // Create a car using the mock engine
        Car car = new Car(mockEngine);

        // Test the car's behavior
        String carStartSound = car.startCar();
        System.out.println(carStartSound); // Output: "Mock Vroom!"
    }
}

In this example, `mock(Engine.class)` creates a mock object that behaves like an `Engine` but doesn't have the real engine's functionality. The `when(mockEngine.start()).thenReturn("Mock Vroom!")` line sets up the mock engine to return `"Mock Vroom!"` when its `start()` method is called.

By using Mockito, you can test the `Car` class's behavior without relying on the real `Engine` class, making your tests faster, more focused, and easier to maintain.


What is the difference between Mockito and JUnit?
  • JUnit and Mockito are widely used testing frameworks in the Java ecosystem, each serving distinct purposes. 
  • JUnit is a unit testing framework that focuses on writing and executing test cases for individual units of code. 
  • Mockito, on the other hand, is a mocking framework specifically designed to create mock objects for testing purposes. 
  • While JUnit focuses on testing individual units of code, Mockito specializes in managing dependencies and mocking external interactions.
  • In summary, JUnit and Mockito are two powerful and complementary testing frameworks for Java applications.

Benefits of Mockito
Mockito is a popular Java mocking framework that allows you to create mock objects for unit testing. Some of the benefits of Mockito include:
  • No handwriting: In Mockito, there is no requirement for writing your mock objects.
  • Safe refactoring: While renaming the method name of an interface or reordering parameters will not break the test code as Mocks are created at run time.
  •  Annotation support: It supports creating mocks using various annotations.
  •  Return value support: Supports return values.
  •  Exception support: It supports exceptions.


Sunday, August 6, 2023

@CsvSource Annotation With @ParameterizedTest in JUnit5





  • The @CsvSource annotation is a way to provide comma-separated values (CSV) as arguments for a parameterized test method in JUnit 5. 
  • It allows you to specify one or more CSV records that will be used as the source of arguments for each invocation of the test method. 
  • You can customize the column delimiter, the quote character, the empty value, and the null values using the annotation attributes. 
  • You can also use a text block to write multiple CSV records in a more readable way.
  • You can use various types of arguments and datatypes, such as primitives, enums, arrays, collections, and custom types. 
  • However, you need to make sure that the arguments can be converted to the target parameter types by using implicit or explicit converters.


Here is an example of how to use the @CsvSource annotation:

import org.junit.jupiter.params.ParameterizedTest;

import org.junit.jupiter.params.provider.CsvSource;

import static org.junit.jupiter.api.Assertions.assertEquals;

class CalculatorTest {

    @ParameterizedTest

    @CsvSource({

        "0,    1,   1",

        "1,    2,   3",

        "49,  51, 100",

        "1,  100, 101"

    })

    void add(int first, int second, int expectedResult) {

        Calculator calculator = new Calculator();

        assertEquals(expectedResult, calculator.add(first, second),

                () -> first + " + " + second + " should equal " + expectedResult);

    }

}


  • This test method will be executed four times with different values for the first, second, and expectedResult parameters. 
  • The values are taken from the CSV records provided by the @CsvSource annotation. 
  • The column delimiter is a comma (,) by default, but you can change it using the delimiter or delimiterString attributes.


Here are some examples of how to use the @CsvSource annotation with different types of arguments and datatypes:


Primitives: You can use primitive types such as int, long, double, boolean, etc. as arguments for the test method. For example:

@ParameterizedTest

@CsvSource({"1, 2, 3", "4, 5, 9", "7, 8, 15"})

void testAdd(int a, int b, int expected) {

    assertEquals(expected, a + b);

}


Enums: You can use enum constants as arguments for the test method. For example:

enum Color {

    RED, GREEN, BLUE

}

@ParameterizedTest

@CsvSource({"RED, 255, 0, 0", "GREEN, 0, 255, 0", "BLUE, 0, 0, 255"})

void testColor(Color color, int r, int g, int b) {

    assertEquals(r, color.getRed());

    assertEquals(g, color.getGreen());

    assertEquals(b, color.getBlue());

}


Arrays: You can use arrays as arguments for the test method by using curly braces ({}) to enclose the array elements. For example:

@ParameterizedTest

@CsvSource({"1, {2, 3}", "4, {5, 6}", "7, {8}"})

void testArray(int a, int[] b) {

    assertTrue(a > 0);

    assertTrue(b.length > 0);

}


Collections: You can use collections such as List or Set as arguments for the test method by using curly braces ({}) to enclose the collection elements. For example:


@ParameterizedTest

@CsvSource({"1, {2, 3}", "4, {5}", "7"})

void testCollection(int a, List<Integer> b) {

    assertTrue(a > 0);

    assertNotNull(b);

}


Custom types: You can use custom types as arguments for the test method by implementing an ArgumentConverter that can convert a String to the custom type. For example:


class Person {

    private String name;

    private int age;

    // constructor and getters omitted for brevity

}


class PersonConverter implements ArgumentConverter {

    @Override

    public Object convert(Object source, ParameterContext context) throws ArgumentConversionException {

        if (!(source instanceof String)) {

            throw new IllegalArgumentException("The argument should be a string: " + source);

        }

        String[] parts = ((String) source).split(":");

        if (parts.length != 2) {

            throw new IllegalArgumentException("The argument should have two parts separated by a colon: " + source);

        }

        String name = parts[0];

        int age = Integer.parseInt(parts[1]);

        return new Person(name, age);

    }

}


@ParameterizedTest

@CsvSource({"Alice:23", "Bob:42", "Charlie:28"})

void testPerson(@ConvertWith(PersonConverter.class) Person person) {

    assertNotNull(person.getName());

    assertTrue(person.getAge() > 0);

}


You can use a different delimiter character or string for the CSV records, such as a semicolon (;) or a pipe (|). For example:

@ParameterizedTest

@CsvSource (delimiter = ';', value = {

    "apple; 1",

    "banana; 2",

    "'lemon; lime'; 3"

})

void testWithSemicolonDelimiter(String fruit, int rank) {

    assertNotNull(fruit);

    assertNotEquals(0, rank);

}


You can use a different quote character for the CSV records, such as a double quote (\"). For example:

@ParameterizedTest

@CsvSource (quoteCharacter = '"', value = {

    "\"apple, banana\"; 1",

    "\"lemon, lime\"; 2"

})

void testWithDoubleQuote(String fruits, int rank) {

    assertTrue(fruits.contains(","));

    assertNotEquals(0, rank);

}


You can use a text block to write multiple CSV records in a more readable way. For example:

@ParameterizedTest

@CsvSource (textBlock = """

    name, age

    Alice, 23

    Bob, 42

    Charlie, 28

""")

void testWithTextBlock(String name, int age) {

    assertNotNull(name);

    assertTrue(age > 0);

}


You can use the nullValues attribute to specify one or more strings that should be interpreted as null references. For example:

@ParameterizedTest

@CsvSource (nullValues = {"NULL", "N/A"}, value = {

    "apple, NULL",

    "banana, N/A",

    "lemon, ''"

})

void testWithNullValues(String fruit, String color) {

    assertNotNull(fruit);

    assertNull(color);

}

You can find more information and examples about the @CsvSource annotation in the [JUnit 5 documentation]. 

Saturday, August 19, 2023

Mockito Mock Method

 


This method is used to create a mock object of a given class or interface. It returns an instance of the specified type with all methods stubbed out.

Mockito is a popular Java library used for unit testing. It allows you to create mock objects to simulate the behavior of real objects and isolate the code you're testing from external dependencies. One of the key features of Mockito is its ability to mock methods, enabling you to define the behavior of mocked methods and verify their interactions.

Here's an explanation and an example of how to use Mockito to mock methods:

1. Creating Mock Objects:

In Mockito, you can create mock objects using the `Mockito.mock()` method.  This method generates a mock instance of the specified class or interface. The mock object behaves as if it were a real instance of the class, but you can define its behavior, such as what methods should return or how they should behave when called.


2. Stubbing Method Behavior:

Mocking a method involves defining what it should return when it's called. This is done using the `when().thenReturn()` syntax. You tell Mockito what method to mock and what value to return when that method is called on the mock object.


3. Verifying Method Calls:

After you've defined the behavior of the mock methods and have used them in your code, you can verify if specific methods were called with the expected arguments. This is done using the `verify()` method in Mockito.

Example:

Suppose you have a `Calculator` class that you want to test. This calculator uses an external `MathService` to perform calculations. Here's how you would use Mockito to mock the `MathService` and test the `Calculator`:


import org.junit.jupiter.api.Test;

import org.mockito.Mockito;

import static org.junit.jupiter.api.Assertions.assertEquals;

import static org.mockito.Mockito.verify;

import static org.mockito.Mockito.when;

public class CalculatorTest {

   @Test

    public void testAdd() {

        // Create a mock MathService

        MathService mathService = Mockito.mock(MathService.class);

        // Stub the behavior of the add method

        when(mathService.add(2, 3)).thenReturn(5);

        // Create a Calculator instance using the mock MathService

        Calculator calculator = new Calculator(mathService);

         // Perform the test

        int result = calculator.add(2, 3);

        // Verify that the mathService.add method was called with the expected arguments

        verify(mathService).add(2, 3);

        // Verify the result

        assertEquals(5, result);

    }

}


In this example, the `MathService` is mocked using `Mockito.mock()`, and its `add` method behavior is defined using `when().thenReturn()`. The test then creates a `Calculator` instance using the mock `MathService`. After performing the calculation, the `verify()` method checks whether the `add` method of the mock was called with the expected arguments.

This example demonstrates how to mock a method's behavior and verify its usage during unit testing using Mockito.