Running JUnit 5 in Gradle Project

Follow the given step to setup JUnit 5 in Gradle project. Newbies wanna read Setup first gradle project in eclipse.

Step 1. Prepare build.gradle for JUnit 5

Step 1.1. Attach JUnit 5 gradle plugin to project.
apply plugin: 'org.junit.platform.gradle.plugin'

buildscript {
    repositories {
        mavenCentral()
    }
    dependencies {
    	// Gradle plugin
        classpath 'org.junit.platform:junit-platform-gradle-plugin:1.0.0-M3'
    }
}
Step 1.2. Add JUnit 5 dependencies.
dependencies {
    // download library for JUnit
    compile group: 'org.junit.jupiter', name: 'junit-jupiter-api', version: '5.0.0-M3'
    compile group: 'org.junit.jupiter', name: 'junit-jupiter-engine', version: '5.0.0-M3'
    compile group: 'org.junit.platform', name: 'junit-platform-runner', version: '1.0.0-M3'
    
    // compile project for testing using Junit Jupiter Api
    testCompile("org.junit.jupiter:junit-jupiter-api:5.0.0-M3")
}
Step 1.3. JUnit 5 configuration.
Properties are self-explanatory.
junitPlatform {
    platformVersion "1.0.0-M3"
    filters {
        engines {
            include 'junit-jupiter'
            // exclude 'junit-vintage'
        }
        tags {
            // include 'fast', 'smoke'
            // exclude 'slow', 'ci'
        }
        packages {
            // include 'com.sample.included1', 'com.sample.included2'
            // exclude 'com.sample.excluded1', 'com.sample.excluded2'
        }
        //includeClassNamePattern '.*Spec'
        includeClassNamePatterns '.*Test', '.*Tests'
    }
}

Complete build.gradle
This is how your build.gradle file will look like after following the above steps.
apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'org.junit.platform.gradle.plugin'

sourceCompatibility = 1.8

repositories {
    mavenCentral()
}

buildscript {
	repositories {
        mavenCentral()
    }
    dependencies {
    	// Gradle plugin
        classpath 'org.junit.platform:junit-platform-gradle-plugin:1.0.0-M3'
    }
}

dependencies {
    // download library for JUnit
    compile group: 'org.junit.jupiter', name: 'junit-jupiter-api', version: '5.0.0-M3'
    compile group: 'org.junit.jupiter', name: 'junit-jupiter-engine', version: '5.0.0-M3'
    compile group: 'org.junit.platform', name: 'junit-platform-runner', version: '1.0.0-M3'
    
    // compile project for test using Junit Jupiter Api
    testCompile("org.junit.jupiter:junit-jupiter-api:5.0.0-M3")
}

junitPlatform {
    platformVersion "1.0.0-M3"
    filters {
        engines {
            include 'junit-jupiter'
            // exclude 'junit-vintage'
        }
        tags {
            // include 'fast', 'smoke'
            // exclude 'slow', 'ci'
        }
        packages {
            // include 'com.sample.included1', 'com.sample.included2'
            // exclude 'com.sample.excluded1', 'com.sample.excluded2'
        }
        //includeClassNamePattern '.*Spec'
        includeClassNamePatterns '.*Test', '.*Tests'
    }
}

Step 2. Refresh dependencies
Refresh Gradle project so it'll download required libraries.

Step 3. Project structure.
Create test source folder parallel to main source folder (i.e src/test/java and src/test/resources). Follow the image.

JUnit Test + Gradle project structure

Step 4. Create first unit test.

Source code (Addition.java)
package com.javaquery.math;

public class Addition {
	/**
	 * Add given number 'a' and 'b'.
	 * @param a
	 * @param b
	 * @return
	 */
	public int add(int a, int b){
	    return a + b;
	}
}
Source code (AdditionTest.java)
I created two test cases. Out of two case one is success and other is fail.
package com.javaquery.math;

import org.junit.jupiter.api.Test;
import org.junit.platform.runner.JUnitPlatform;
import org.junit.runner.RunWith;
import static org.junit.jupiter.api.Assertions.assertEquals;

@RunWith(JUnitPlatform.class)
public class AdditionTest {

	@Test
	public void add(){
	    int x = new Addition().add(12, 3);
	    assertEquals(x, 15);
	}
	
	@Test
	public void failTest(){
	    int y = new Addition().add(20, 30);
	    assertEquals(y, 20);
	}
}

Step 5. Clean and Test
Perform clean and test task on your gradle project.
clean
test

Output
[sts] -----------------------------------------------------
[sts] Starting Gradle build for the following tasks: 
[sts]      clean
[sts]      test
[sts] -----------------------------------------------------
:clean
:compileJava
:processResources UP-TO-DATE
:classes
:compileTestJava
:processTestResources UP-TO-DATE
:testClasses
:junitPlatformTestJan 01, 2017 11:48:00 PM org.junit.platform.launcher.core.ServiceLoaderTestEngineRegistry loadTestEngines
INFO: Discovered TestEngines with IDs: [junit-jupiter]


Failures (1):
  JUnit Jupiter:AdditionTest:failTest()
    MethodSource [className = 'com.javaquery.math.AdditionTest', methodName = 'failTest', methodParameterTypes = '']
    => org.opentest4j.AssertionFailedError: expected: <50> but was: <20>

Test run finished after 105 ms
[         2 containers found      ]
[         0 containers skipped    ]
[         2 containers started    ]
[         0 containers aborted    ]
[         2 containers successful ]
[         0 containers failed     ]
[         2 tests found           ]
[         0 tests skipped         ]
[         2 tests started         ]
[         0 tests aborted         ]
[         1 tests successful      ]
[         1 tests failed          ]

:junitPlatformTest FAILED

Setup first gradle project in eclipse


Gradle (Modern Open Source Build Tool for Continuous Delivery)
Built over the concepts of Apache Ant and Apache Maven. It helps you with build process of project. Using Gradle you can perform tasks like

  • Build project and its sub projects.
  • Test the build.
  • Execute customized task like you do with any other programming language using.
Gradle uses Groovy Programming language for project configuration.

Step 1. Download Gradle
Download latest binary distribution from https://www.gradle.org/gradle-download/

Step 2. Extract the binary.
Extract the downloaded binary in say C:\gradle-3.2.1.

Step 3. Setup Gradle eclipse preference.
In Eclipse go to Window > Preferences > Gradle (STS) > Folder.


Step 4. Download eclipse gradle plugin.
In Eclipse go to Help > Eclipse Marketplace and search for gradle. There is official eclipse plugin from gradle however I prefer the gradle plugin developed by Spring as a part of Sprint Tool Suits (STS).


Step 5. Create new Gradle project.
Go to File > New > Other > Gradle (STS) > Gradle (STS) Project.


Step 6. Specify your first gradle project name.


Step 7. Upgrade Java version
Sample gradle project is configured to use Java 1.5 so change it to your system's Java version. Open build.gradle and change sourceCompatibility = 1.5 to sourceCompatibility = 1.8

Step 8. Refresh gradle project.

Right click on Project and go to Gradle (STS) > Refresh All.



How to get current working directory path in Java?

Following excerpt show how to get current working directory path in Java using java.nio.file.Path (Java 7 or up).

Source code (CurrentWorkingDirectory.java)
import java.nio.file.Path;
import java.nio.file.Paths;

/**
 * Get current working directory path.
 * @author javaQuery
 * @date 27th December, 2016
 * @Github: https://github.com/javaquery/Examples
 */
public class CurrentWorkingDirectory {

    public static void main(String[] args) {
        Path path = Paths.get("");
        String currentWorkingDirectory = path.toAbsolutePath().toString();
        System.out.println("Current working directory: " + currentWorkingDirectory);
    }
}

Output
Current working directory: C:\Users\Vicky\Documents\NetBeansProjects\Examples

How to read from console in Java?

Following excerpt shows how you can read String, Number, etc... from console in Java using java.util.Scanner.

Source code (ScannerExample.java)
import java.util.Scanner;

/**
 * Example of scanner in Java.
 * @author javaQuery
 * @date 27th December, 2016
 * @Github: https://github.com/javaquery/Examples
 */
public class ScannerExample {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        
        System.out.println("Username:");
        String username = scanner.nextLine();
        System.out.println("Password:");
        String password = scanner.nextLine();
        System.out.println("Enter random number(Read interger from console):");
        int number = scanner.nextInt();
        
        System.out.println("[Username:" + username + ", Password: " + password + ", Number: " + number + "]");
    }
}

Output
Username:
vicky.thakor
Password:
pass1word
Enter random number(Read interger from console):
123456
[Username:vicky.thakor, Password: pass1word, Number: 123456]

What is SQL Injection and how to avoid it in Java?

SQL Injection
Its a technique where attacker try to alter(modify/change) your SQL query using input parameters.
SQL injection may leads to unexpected transaction (i.e select, update, delete, etc...). We'll see the basic SQL injection examples and later on see how to prevent it using Prepared Statement, Hibernate Criteria and HQL.

Source code (SQLInjection.java)
import java.util.ArrayList;
import java.util.List;

/**
 * Example of SQL injection.
 * @author javaQuery
 * @date 8th November, 2016
 * @Github: https://github.com/javaquery/Examples
 */
public class SQLInjection {

    public static void main(String[] args) {
        /* You are getting parameter value from web page or other user input */
        String parameter = "12"; // normal condition
        new SQLInjection().getUser(parameter);

        /**
         * SQL injection using parameter value. 
         * - If user can change parameter in url, use some script, etc...
         */
        parameter = "12 or 1 = 1";
        new SQLInjection().getUser(parameter);
    }

    /**
     * Get user from database.
     * @param id
     * @return 
     */
    public List<Object> getUser(String id) {
        List<Object> result = new ArrayList<Object>();

        String sql = "SELECT * FROM users WHERE id = " + id + ";";
        System.out.println("SQL Query: " + sql);

        /* prepare connection and execute query */
        return result;
    }
}
Output
In following queries, 1st query is valid and return result as expected but when 2nd query is executed it'll select all users from database and that may leads to unexpected behavior of your system.
SQL Query: SELECT * FROM users WHERE id = 12;
SQL Query: SELECT * FROM users WHERE id = 12 or 1 = 1;
In this example I used user table and this table contains very few records 1k, 10k, etc... but
What if you are selecting data from table which contains millions of records? - Answer is SYSTEM CRASH

Other ways of SQL injection
Consider you are getting value of username and password from parameter into param_username and param_password.
String param_username = "\" or \"\"=\"";
String param_password = "\" or \"\"=\"";

//SQL Injection:
String sql = "SELECT * FROM users WHERE username = \"" + param_username + "\" AND password = \"" + param_password +"\"";
System.out.println(sql);
//OUTPUT: SELECT * FROM users WHERE username = "" or ""="" AND password = "" or ""=""

============================================
String param_userid = "123; DROP TABLE messages;";

//SQL Injection:
String sql = "SELECT * FROM users WHERE id = " + param_userid;
System.out.println(sql);
//OUTPUT: SELECT * FROM users WHERE id = 123; DROP TABLE messages;

First and foremost way: Handle Datatypes
For the sake of simplicity developers don't handle data types at coding. In above code I used String as input parameter in method getUser but should've use Integer/Long. If I used Integer or Long then I've to convert String => 12 or 1 = 1 to Integer/Long => Not Valid Number. It'll prevent SQL Injection.


Avoid SQL Injection using Prepared Statement
Prepared Statement doesn't append values in your SQL query rather it provide SQL query and parameter values separately to database. Database will take care of every parameter value for escape character, special character and every other precaution needed.

Source code (PreparedStatementExample.java)
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

/**
 * Example of SQL injection.
 * @author javaQuery
 * @date 8th November, 2016
 * @Github: https://github.com/javaquery/Examples
 */
public class PreparedStatementExample {
    public static void main(String[] args) {
        new PreparedStatementExample().getUser("12");
    }
    
    /**
     * Get user from database.
     * @param id
     * @return 
     */
    public List<Object> getUser(String id) {
        List<Object> result = new ArrayList<Object>();

        String sql = "SELECT * FROM users where id = ?;";

        /* prepare connection and execute query */
        try {
            Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/demo", "root", "root");
            PreparedStatement prepareStatement = connection.prepareStatement(sql);
            prepareStatement.setInt(1,Integer.parseInt(id)); // index of ? is '1', perform null/number check for 'id'
            //execute prepared statement
        } catch (SQLException ex) {
            ex.printStackTrace();
        }
        
        return result;
    } 
}
Output
With PreparedStatement only following query can be generated.
SELECT * FROM users where id = 12;
prepareStatement.setInt: 12 or 1 = 1 is passed as value then Integer.parseInt will throw java.lang.NumberFormatException: For input string: "12 or 1=1".
prepareStatement.setString: What happen if String is used for Number data type in MySQL?


Avoid SQL Injection using Hibernate Criteria
Hibernate Criteria internally uses Prepared Statement to execute query.

Source code
String param_id = "12";

Criteria criteria = session.createCriteria(User.class);
/**
 * 'param_id' provided as String but 'id' declared as Integer/Long in User.java
 * So it'll throw exception(java.lang.String cannot be cast to java.lang.Integer) for invalid data type. (SQL injection handled)
 */
criteria.add(Restrictions.eq("id", param_id));
User user = criteria.uniqueResult();

==============================

// valid query
Integer param_id = 12;

Criteria criteria = session.createCriteria(User.class);
criteria.add(Restrictions.eq("id", param_id));
User user = criteria.uniqueResult();

Avoid SQL Injection using HQL
Its same as Hibernate Criteria.

Source code
String param_id = "12";

Query query = session.createQuery("FROM User WHERE id = :param_id");
/**
 * 'param_id' provided as String but 'id' declared as Integer/Long in User.java
 * So it'll throw exception(java.lang.String cannot be cast to java.lang.Integer) for invalid data type. (SQL injection handled)
 */
query.setParameter("param_id", param_id);
query.list();

==============================

// valid query
Integer param_id = 12;

Query query = session.createQuery("FROM User WHERE id = :param_id");
query.setParameter("param_id", param_id);
query.list();

What happen if String is used for Number data type in MySQL?

String for Number datatype in MySQL

For Number data type, MySQL parse String value character-by-character until it finds character other than number.

Queries
SELECT * FROM users WHERE id = '12 or 1=1'; \\ 1 -> OK, 2 -> OK,  -> false-and-return
> SELECT * FROM users WHERE id = 12;

SELECT * FROM users WHERE id = '123XYZ'; \\ 1 -> OK, 2 -> OK, 3 -> OK, X -> false-and-return
> SELECT * FROM users WHERE id = 123;

SELECT * FROM users WHERE id = '1&23XYZ'; \\ 1 -> OK, & -> false-and-return
> SELECT * FROM users WHERE id = 1'

How to sum values from List, Set and Map using stream in Java 8?



Following examples shows how you can use java 8 Stream api to do summation of Integer, Double and Long in List, Set and Map.

Source code (Item.java)
public class Item {

    private Long id;
    private String name;
    private Double price;
    
    public Item(String name, Double price) {
        this.name = name;
        this.price = price;
    }
    
    /* getter - setter */

    public Double getPrice() {
        return price;
    }

    public void setPrice(Double price) {
        this.price = price;
    }
}

List
  • Summation of Integers in List.
  • Summation of Price from List of beans(Item).

Source code (ListStreamSum.java)
import com.javaquery.bean.Item;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * Summation of element in List using Stream api in java 8.
 *
 * @author javaQuery
 * @date 17th October, 2016
 * @Github: https://github.com/javaquery/Examples
 */
public class ListStreamSum {

    public static void main(String[] args) {
        /* Summation of Integers in List */
        List<Integer> integers = new ArrayList<>(Arrays.asList(10, 20, 30));

        Integer integerSum = integers.stream().mapToInt(Integer::intValue).sum();
        System.out.println("summation: " + integerSum);

        /* Summation when you have list of beans */
        Item motoG = new Item("MotoG", 100.12);
        Item iPhone = new Item("iPhone", 200.12);

        List<Item> listBeans = new ArrayList<>(Arrays.asList(motoG, iPhone));

        Double doubleSum = listBeans.stream().mapToDouble(Item::getPrice).sum();
        System.out.println("summation: " + doubleSum);
    }
}

Output
summation: 60
summation: 300.24

Set
  • Summation of Integers in Set.
  • Summation of Price from Set of beans(Item).

Source code (SetStreamSum.java)
import com.javaquery.bean.Item;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;

/**
 * Summation of element in Set using Stream api in java 8.
 *
 * @author javaQuery
 * @date 17th October, 2016
 * @Github: https://github.com/javaquery/Examples
 */
public class SetStreamSum {

    public static void main(String[] args) {
        /* Summation of Integers in Set */
        Set<Integer> integers = new HashSet<>(Arrays.asList(10, 20, 30));

        Integer integerSum = integers.stream().mapToInt(Integer::intValue).sum();
        System.out.println("summation: " + integerSum);

        /* Summation when you have set of beans */
        Item motoG = new Item("MotoG", 100.12);
        Item iPhone = new Item("iPhone", 200.12);

        Set<Item> listBeans = new HashSet<>(Arrays.asList(motoG, iPhone));

        Double doubleSum = listBeans.stream().mapToDouble(Item::getPrice).sum();
        System.out.println("summation: " + doubleSum);
    }
}

Output
summation: 60
summation: 300.24

Map
  • Summation of Integers in Map as a value.
  • Summation of Integers in List as a value.
  • Summation of Price from List of beans(Item) in Map.

Source code (MapStreamSum.java)
import com.javaquery.bean.Item;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Summation of element in Map using Stream api in java 8.
 *
 * @author javaQuery
 * @date 17th October, 2016
 * @Github: https://github.com/javaquery/Examples
 */
public class MapStreamSum {

    public static void main(String[] args) {
        /* Summation of Integers in Map */
        Map<String, Integer> integers = new HashMap<>();
        integers.put("A", 10);
        integers.put("B", 20);
        integers.put("C", 30);

        Integer integerSum = integers.values().stream().mapToInt(Integer::intValue).sum();
        System.out.println("summation: " + integerSum);

        /* Summation when you have List/Set in Map */
        Map<String, List<Integer>> listInMap = new HashMap<>();
        listInMap.put("even_numbers", new ArrayList<>(Arrays.asList(2, 4, 6)));

        integerSum = listInMap.values().stream()
                .flatMapToInt(list -> list.stream().mapToInt(Integer::intValue))
                .sum();
        System.out.println("summation: " + integerSum);

        /* Summation when you have List/Set of beans in Map */
        Item motoG = new Item("MotoG", 100.12);
        Item iPhone = new Item("iPhone", 200.12);

        List<Item> items = new ArrayList<>(Arrays.asList(motoG, iPhone));

        Map<String, List<Item>> itemMap = new HashMap<>();
        itemMap.put("items", items);

        Double doubleSum = itemMap.values().stream()
                .flatMapToDouble(list -> list.stream().mapToDouble(Item::getPrice))
                .sum();
        System.out.println("summation: " + doubleSum);
    }
}

Output
summation: 60
summation: 12
summation: 300.24