Avoid multithreading problems in Java using ThreadLocal

Last Updated on by

Post summary: What are common approaches to deal with multithreading problems in Java. What is ThreadLocal and how to use it.

Multithreading problems

By definition multithreading is ability of CPU to execute multiple processes and threads. Almost every application nowadays is multithreaded. This allows programs to be faster and handler more users, programs have more complex design. Multithreading causes race conditions (performing many operations at the same time on one resource) and deadlocks (competitive actions wait for each other to finish).

Multithreading problem

See code snippet bellow. This is simple utility class that converts Date to String. When functional or unit tests are executed on it there are no issues, since in most cases those are single threaded. When performance test is run program will burst into flames. Problem is that SimpleDateFormat is not thread safe. Java 8 date objects are thread safe as they are immutable, but Java 7 bellow are not:

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;

public final class DateTimeUtils {

	private static final SimpleDateFormat DATE_FORMAT
			= new SimpleDateFormat("yyyy-MM-dd", Locale.ENGLISH);

	private DateTimeUtils() {
		// Util class
	}

	public static String toDateString(Date date) {
		return DATE_FORMAT.format(date);
	}
}

Avoid multithreading problems

Debugging multithreading problems is really hard. During debug there are no race conditions and program works correctly. Program can even work correctly with small amount of users. One clue for multithreading problems is NullPointerException in places in a code where it is impossible to have such. Prevention is better than debugging. Prevention suggests proper design. Bellow is a list with approaches how to prevent and avoid multithreading issues:

  • Immutable objects
  • Defensive copies
  • Synchronized
  • Volatile
  • Atomic operations
  • ThreadLocal

Immutable objects

Immutable means something that cannot change. Values in such objects are initialised once and never changed, just read. Date objects in Java 8 are immutable which makes them safe to use. Object bellow is example of immutable one:

public class Immutable {

	private String name;

	public Immutable(String name) {
		this.name = name;
	}

	public String getName() {
		return name;
	}
}

Going back to initial problem with DateTimeUtils one solution could be to always create new SimpleDateFormat object:

public static String toDateString(Date date) {
	return new SimpleDateFormat("yyyy-MM-dd", Locale.ENGLISH).format(date);
}

Defensive copies

Immutable objects are really simple and their fields should be primitive data types, which is not always possible. If some filed is object (List) getter will return copy of reference to this object, but actual object can be still manipulated in heap. In such cases defensive copies are returned:

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class Immutable {

	private String name;
	private List<String> hobbies;

	public Immutable(String name, String... hobbies) {
		this.name = name;
		this.hobbies = new ArrayList<>();
		Collections.addAll(this.hobbies, hobbies);
	}

	public String getName() {
		return name;
	}

	public List<String> getHobbies() {
		return new ArrayList<>(hobbies);
	}
}

Example here works as ArrayList is from String. If it was from some Object only references would be copied from one list to other, again real object would be available in heap, so deep copy of the Object data is also needed. Copy should drill down to the primitive types.

Synchronized

Synchronized methods cannot be access from two thread at the same time. One thread can access the synchronized object method, others are blocked and wait. Another solution to DateTimeUtils problem could be using synchronized:

private static final SimpleDateFormat DATE_FORMAT
            = new SimpleDateFormat("yyyy-MM-dd", Locale.ENGLISH);

public static synchronized String toDateString(Date date) {
	return DATE_FORMAT.format(date);
}

Theoretically this should work and when testing locally it does, but I’ve seen this solution not working in real life application, so I would not go for synchronized in given problem context.

Volatile

Volatile means that variable is stored in main memory. I would not go into details for this solution. It is pretty complex and has unexpected problems.

Atomic operations

The Java language specification guarantees that reading or writing a variable is an atomic operation (unless the variable is of type long or double because of some CPU architecture specifics). For example i++ is not atomic operation, it consist of two operations – read the value and add 1 to it. In order to be sure you use atomic operations on variables Java provides whole package with atomic objects java.util.concurrent.atomic. Obects have methods like getAndSet(), getAndIncrement() and getAndDecrement() which ensure thread safety.

ThreadLocal

This was the topic initially blog post was about, but with the research it got little extended. This class provides thread-local variables or in other words variables that are actually different for each and every thread. It is little strange, because declaration suggests this is one variable but Java makes copies behind the scenes. There is also InheritableThreadLocal which means variable is different for other threads, but one and the same for current thread and its sub-threads. This could also lead to multithreading problems if you mess the thread-local object from the sub-threads. Third solution to DateTimeUtils problem could be:

private static final ThreadLocal<SimpleDateFormat> DATE_FORMAT
		= new ThreadLocal<SimpleDateFormat>() {
	@Override
	protected SimpleDateFormat initialValue() {
		return new SimpleDateFormat("yyyy-MM-dd", Locale.ENGLISH);
	}
};

public static String toDateString(Date date) {
	return DATE_FORMAT.get().format(date);
}

Or using new Java 8 lambda expressions code will look as bellow. More on Java 8 features can be found in Java 8 features – Lambda expressions, Interface changes, Stream API, DateTime API post.

private static final ThreadLocal<SimpleDateFormat> DATE_FORMAT_SAFE = ThreadLocal
	.withInitial(() -> new SimpleDateFormat("yyyy-MM-dd", Locale.ENGLISH));

public static String toDateString(Date date) {
	return DATE_FORMAT.get().format(date);
}

Comparison on solutions to multithreading problem

I have given three solutions to DateTimeUtils multithreading problem. Code shown above is available in GitHub java-samples/junit repository. There is unit test DateTimeUtilsTest which is run in multithreading mode with Maven Surefire Plugin and tests the solutions. 10 tests are run in 10 separate threads. Each test makes 1000 invocations of toDateString() method with unique date. Java 8 LocalDate is used in tests to confirm thread safety. Here are thoughts and time for different solutions:

  • synchronized (toDateStringSynchronized) – time to execute tests is 0.091 – 0.101s. I would not go for this solution as I stated above I’ve seen it not working in real life application. Also just theoretically since threads have to wait on each other performance will suffer.
  • new object on each method call (toDateStringNewObject) – time to execute tests is 0.114 – 0.124s. Object creation could be expensive operation. In this case there are 10000 objects created, compared to 1 in synchronized version and 10 in ThreadLocal version.
  • ThreadLocal (toDateStringThreadLocal) – time to execute tests is 0.75 – 0.82s. This is my favourite. There is no wait on threads and very low amount of objects are created.

Observations above are valid for given multithreading problem, not a general rule. Everything is up to the problem that needs to be solved.

Conclusion

Multithreading is very advanced topic. In this post I have just given some overview and examples that could be easily applied in automation code. I would encourage you to use ThreadLocal to prevent multithreading problems. In production code things could be much more complex. Very good tutorial on multithreading can be found in Java Concurrency / Multithreading Tutorial.

Read more...

Performance testing with Gatling – reports

Last Updated on by

Post summary: Some details on Gatling results report.

Current post is part of Performance testing with Gatling series in which Gatling performance testing tool is explained in details.

If you have followed the Gatling series so far you should know how to record a simulation, what simulation consists of, how to create Maven project and make code well structured and maintainable. Now is the time to run that code and see the results.

Gatling global information

Gatling has pretty cool looking report. It shows global information about simulation as long as more detailed information for each request or request group. This is how global information looks like:

Gatling-reports-global

Shown above is just part of global information report page. There are following sections on it:

  • Indicators – distribution in specified response time intervals: less than 800ms, 800ms – 1200ms, more 1200ms and failed. This can give you general overview of the system performance. If highest percentage of the responses are less than 800ms this is quite good performance indication.
  • Number of requests – pie chart showing different request types. This gives visual information how many request of different type are being sent. Type is actually the request name defined in http() method.
  • STATISTICS – table with very detailed information what count of each request type has been sent, OK, KO count, KO percentage. There is information what is the best, worst and mean time for each request type. Since worst time could be for a single response this is not quite informative. This is why there is grouping what is the response time for 95% and 99% of the responses. Last information is request per second.
  • Active Users along the Simulation – how many virtual users were sending requests at each moment during the simulation. There is also user count per scenario. Scenario is identified by its name defined in scenario() method.
  • Response Time Distribution – detailed responses distribution in small time intervals. Pretty similar as Indicators one, but much more detailed, as time intervals are very small. This gives much better perspective of performance as you can see what percentage of the requests are in given time bucket. This graphic also includes error requests as well.
  • Response Time Percentiles over Time (OK) – minimum and maximum request time at each moment during simulation only for successful (OK) requests. There is also request grouping into percentage values showing what percent of the requests take given amount of time. Similar to STATISTICS table, but here there is much more detailed grouping and also you can see it distributed during simulation execution. Additionally this graphic shows number of user at each moment during simulation.
  • Number of requests per second – how many requests are done to the server at each moment during simulation. There is separate graphics for all requests, OK and KO requests. Additionally this graphic shows number of user at each moment during simulation.
  • Number of responses per second – how many responses are done to the server at each moment during simulation. There is separate graphics for all responses, OK and KO responses. Additionally this graphic shows number of user at each moment during simulation.

Gatling request details

Apart from global information there is detailed report for each request type. Requests are sorted by name used when defining the HTTP request in http() method. This is how request details look like:

Gatling-reports-details

Shown above is just part of request details report page. There are following sections on it:

  • Indicators – same as in global information
  • STATISTICS – same as in global information but just timing for this particular request are shown.
  • Response Time Distribution – same as in global information
  • Response Time Percentiles over Time (OK) – same as in global information
  • Latency Percentiles over Time (OK) – same as Response Time Percentiles over Time (OK), but showing the time needed for the server to process the request, although it is incorrectly called latency. By definition Latency + Process Time = Response time. So this graphic is supposed to give the time needed for request to reach the server. Checking real life graphics I think this graphic shows not the Latency, but the real Process Time. You can get idea of the real Latency by taking one and the same second from Response Time Percentiles over Time (OK) and subtract values from current graphs for the same second.
  • Number of requests per second – same as in global information
  • Number of responses per second – same as in global information
  • Response Time against Global RPS – distribution of current request’s response time related to total request per second of the simulation.
  • Latency against Global RPS – distribution of current request’s latency (process time) related to total request per second of the simulation.

Gatling data in simulation.log file

As you will see in the previous two sections Gatling gathers very limited amount of data, how many requests are made per any given time of the execution, are the responses OK or KO, what time each request and response take. All this information is stored into simulation.log file. Although file is plain text data in it is understandable only by Gatling. In Performance testing with Gatling – advanced usage post it is shown how you can extract more details from request and response. This gets recorded in simulation.log file, so be careful when do this as this file might get enormous. View sample simulation.log file or sample Gatling report.

Conclusion

Gatling report is valuable source of information to read the performance data by providing some details about requests and responses timing. Report should not be your main tool for finding issues when doing performance testing though. It is a good idea to have a server monitoring tool that gives more precise information about memory consumption and CPU. In case of bottlenecks identified by Gatling it is mandatory to do some profiling of the application to understand what action on server take longest time.

Read more...

Performance testing with Gatling – advanced usage

Last Updated on by

Post summary: Code samples and explanation how to do advanced performance testing with Gatling, such like proper scenarios structure, checks, feeding test data, session maintenance, etc.

Current post is part of Performance testing with Gatling series in which Gatling performance testing tool is explained in details.

Code samples are available in GitHub sample-performance-with-gatling repository.

In previous post Performance testing with Gatling – integration with Maven there is description how to setup Maven project. In Performance testing with Gatling – recorded simulation explanation there is information what a simulation consist of. Simulations from this post will be refactored in current post and more advanced topics will be discussed how to make flexible automation testing with Gatling.

What is included

Following topics are included in current post:

  • Access external configuration data
  • Define single HTTP requests for better re-usability
  • Add checks for content on HTTP response
  • Check and extract data from HTTP response
  • More checks and extract List with values
  • Create HTTP POST request with body from template file
  • Manage session variables
  • Standard CSV feeder
  • Create custom feeder
  • Create unified scenarios
  • Conditional scenario execution
  • Only one HTTP protocol
  • Extract data from HTTP request and response
  • Advanced simulation setUp
  • Virtual users vs requests per second

Refactored code

Bellow are all classes that are created after they have been refactored. In order to separate things and make it easier to read ProductSimulation and PersonSimulation classes contain only the setUp() method. Request, scenarios and external configurations are being defined into Constants, Product and Person singleton objects.

Constants

object Constants {
	val numberOfUsers: Int = System.getProperty("numberOfUsers").toInt
	val duration: FiniteDuration = System.getProperty("durationMinutes").toInt.minutes
	val pause: FiniteDuration = System.getProperty("pauseBetweenRequestsMs").toInt.millisecond
	val responseTimeMs = 500
	val responseSuccessPercentage = 99
	private val url: String = System.getProperty("url")
	private val repeatTimes: Int = System.getProperty("numberOfRepetitions").toInt
	private val successStatus: Int = 200
	private val isDebug = System.getProperty("debug").toBoolean

	val httpProtocol = http
		.baseURL(url)
		.check(status.is(successStatus))
		.extraInfoExtractor { extraInfo => List(getExtraInfo(extraInfo)) }

	def createScenario(name: String, feed: FeederBuilder[_], chains: ChainBuilder*): ScenarioBuilder = {
		if (Constants.repeatTimes > 0) {
			scenario(name).feed(feed).repeat(Constants.repeatTimes) {
				exec(chains).pause(Constants.pause)
			}
		} else {
			scenario(name).feed(feed).forever() {
				exec(chains).pause(Constants.pause)
			}
		}
	}

	private def getExtraInfo(extraInfo: ExtraInfo): String = {
		if (isDebug
			|| extraInfo.response.statusCode.get != successStatus
			|| extraInfo.status.eq(Status.apply("KO"))) {
			",URL:" + extraInfo.request.getUrl +
				" Request: " + extraInfo.request.getStringData +
				" Response: " + extraInfo.response.body.string
		} else {
			""
		}
	}
}

Product

object Product {

	private val reqGoToHome = exec(http("Open home page")
		.get("/products")
		.check(regex("Search: "))
	)

	private val reqSearchProduct = exec(http("Search product")
		.get("/products?q=${search_term}&action=search-results")
		.check(regex("Your search for '${search_term}' gave ([\\d]{1,2}) results:").saveAs("numberOfProducts"))
		.check(regex("NotFound").optional.saveAs("not_found"))
	)

	private val reqOpenProduct = exec(session => {
		var numberOfProducts = session("numberOfProducts").as[String].toInt
		var productId = Random.nextInt(numberOfProducts) + 1
		session.set("productId", productId)
	}).exec(http("Open Product")
		.get("/products?action=details&id=${productId}")
		.check(regex("This is 'Product ${productId} name' details page."))
	)
	
	private val csvFeeder = csv("search_terms.csv").circular.random

	val scnSearch = Constants.createScenario("Search", csvFeeder,
		reqGoToHome, reqSearchProduct, reqGoToHome)

	val scnSearchAndOpen = Constants.createScenario("Search and Open", csvFeeder,
		reqGoToHome, reqSearchProduct, reqOpenProduct, reqGoToHome)
}

ProductSimulation

class ProductSimulation extends Simulation {

	setUp(
		Product.scnSearch.inject(rampUsers(Constants.numberOfUsers) over 10.seconds),
		Product.scnSearchAndOpen.inject(atOnceUsers(Constants.numberOfUsers))
	)
		.protocols(Constants.httpProtocol.inferHtmlResources())
		.pauses(constantPauses)
		.maxDuration(Constants.duration)
		.assertions(
			global.responseTime.max.lessThan(Constants.responseTimeMs),
			global.successfulRequests.percent.greaterThan(Constants.responseSuccessPercentage)
		)
}

Person

object Person {

	private val added = "Added"
	private val updated = "Updated"

	private val reqGetAll = exec(http("Get All Persons")
		.get("/person/all")
		.check(regex("\"firstName\":\"(.*?)\"").count.greaterThan(1).saveAs("count"))
		.check(regex("\\[").count.is(1))
		.check(regex("\"id\":([\\d]{1,6})").findAll.saveAs("person_ids"))
	).exec(session => {
		val count = session("count").as[Int]
		val personIds = session("person_ids").as[List[Int]]
		val personId = personIds(Random.nextInt(count)).toString.toInt
		session.set("person_id", personId)
	}).exec(session => {
		println(session)
		session
	})

	private val reqGetPerson = exec(http("Get Person")
		.get("/person/get/${person_id}")
		.check(regex("\"firstName\":\"(.*?)\"").count.is(1))
		.check(regex("\\[").notExists)
	)

	private val reqSavePerson = exec(http("Save Person")
		.post("/person/save")
		.body(ElFileBody("person.json"))
		.header("Content-Type", "application/json")
		.check(regex("Person with id=([\\d]{1,6})").saveAs("person_id"))
		.check(regex("\\[").notExists)
		.check(regex("(" + added + "|" + updated + ") Person with id=").saveAs("action"))
	)

	private val reqGetPersonAferSave = exec(http("Get Person After Save")
		.get("/person/get/${person_id}")
		.check(regex("\"id\":${person_id}"))
		.check(regex("\"firstName\":\"${first_name}\""))
		.check(regex("\"lastName\":\"${last_name}\""))
		.check(regex("\"email\":\"${email}\""))
	)

	private val reqGetPersonAferUpdate = exec(http("Get Person After Update")
		.get("/person/get/${person_id}")
		.check(regex("\"id\":${person_id}"))
	)

	private val uniqueIds: List[String] = Source
		.fromInputStream(getClass.getResourceAsStream("/account_ids.txt"))
		.getLines().toList

	private val feedSearchTerms = Iterator.continually(buildFeeder(uniqueIds))

	private def buildFeeder(dataList: List[String]): Map[String, Any] = {
		Map(
			"id" -> (Random.nextInt(100) + 1),
			"first_name" -> Random.alphanumeric.take(5).mkString,
			"last_name" -> Random.alphanumeric.take(5).mkString,
			"email" -> Random.alphanumeric.take(5).mkString.concat("@na.na"),
			"unique_id" -> dataList(Random.nextInt(dataList.size))
		)
	}

	val scnGet = Constants.createScenario("Get all then one", feedSearchTerms,
		reqGetAll, reqGetPerson)

	val scnSaveAndGet = Constants.createScenario("Save and get", feedSearchTerms, reqSavePerson)
		.doIfEqualsOrElse("${action}", added) {
			reqGetPersonAferSave
		} {
			reqGetPersonAferUpdate
		}
}

PersonSimulation

class PersonSimulation extends Simulation {

	setUp(
		Person.scnGet.inject(atOnceUsers(Constants.numberOfUsers)),
		Person.scnSaveAndGet.inject(atOnceUsers(Constants.numberOfUsers))
	)
		.protocols(Constants.httpProtocol)
		.pauses(constantPauses)
		.maxDuration(Constants.duration)
		.assertions(
			global.responseTime.max.lessThan(Constants.responseTimeMs),
			global.successfulRequests.percent.greaterThan(Constants.responseSuccessPercentage)
		)
}

Access external configuration data

In order to have flexibility it is mandatory to be able to sent different configurations parameters from command line when invoking the scenario. With Gatling Maven plugin it is done with  configurations. See more in Performance testing with Gatling – integration with Maven post.

val numberOfUsers: Int = System.getProperty("numberOfUsers").toInt
val duration: FiniteDuration = System.getProperty("durationMinutes").toInt.minutes
private val url: String = System.getProperty("url")
private val repeatTimes: Int = System.getProperty("numberOfRepetitions").toInt
private val isDebug = System.getProperty("debug").toBoolean

Define single HTTP requests for better re-usability

It is good idea to define each HTTP request as a separate object. This gives flexibility to reuse one and the same requests in different scenarios. Bellow is shown how to create HTTP GET request with http().get().

Add checks for content on HTTP response

On HTTP request creation there is possibility to add checks that certain string or regular expression pattern exists in response. Code bellow created HTTP Request and add check that “Search: “ text exists in response. This is done with regex() method by passing just a string to it.

private val reqGoToHome = exec(http("Open home page")
	.get("/products")
	.check(regex("Search: "))
)

Check and extract data from HTTP response

It is possible along with the check to extract data into a variable that is being saved to session. This is done with saveAs() method. In some cases value we are searching for, might not be in the response. We can use optional method to specify that value is saved in session only if existing, if not existing it won’t be captured and this will not break the execution. As shown bellow session variables can be also used in the checks. Session variable is accessed with ${},  such as ${search_term}.

private val reqSearchProduct = exec(http("Search product")
	.get("/products?q=${search_term}&action=search-results")
	.check(regex("Your search for '${search_term}' gave ([\\d]{1,2}) results:")
		.saveAs("numberOfProducts"))
	.check(regex("NotFound").optional.saveAs("not_found"))
)

More checks and extract List with values

There are many type of checks. In code bellow count.greaterThan(1) and count.is(1) are used. It is possible to search for multiple occurrences of given regular expression with findAll. In such case saveAs() saves the results to a “person_ids” List object in session. More information about checks be found in Gatling Checks page.

private val reqGetAll = exec(http("Get All Persons")
	.get("/person/all")
	.check(regex("\"firstName\":\"(.*?)\"").count.greaterThan(1).saveAs("count"))
	.check(regex("\\[").count.is(1))
	.check(regex("\"id\":([\\d]{1,6})").findAll.saveAs("person_ids"))
)

Create HTTP POST request with body from template file

If you need to post data to server HTTP POST request is to be used. Request is created with http().post() method. Headers can be added to request with header() or headers() methods. In current example without Content-Type=application/json header REST service will throw an error for unrecognised content. Data that will be sent is added with body() method. It accepts Body object. You can generate body from file (RawFileBody method) or string (StringBody method).

private val reqSavePerson = exec(http("Save Person")
	.post("/person/save")
	.body(ElFileBody("person.json"))
	.header("Content-Type", "application/json")
	.check(regex("Person with id=([\\d]{1,6})").saveAs("person_id"))
	.check(regex("\\[").notExists)
	.check(regex("(" + added + "|" + updated + ") Person with id=")
		.saveAs("action"))
)

In current case body is generated from file, which have variables that can be later on found in session. This is done with ElFileBody (ELFileBody in 2.0.0) method and actual replace with value is done by Gatling EL (expression language). More about what can you do with EL can be found on Gatling EL page. EL body file is shown bellow, where variables ${id}, ${first_name}, ${last_name} ${email} are searched in session and replaced if found. If not found error is shown on scenario execution output.

{
	"id": "${id}",
	"firstName": "${first_name}",
	"lastName": "${last_name}",
	"email": "${email}"
}

Manage session variables

Each virtual user has it own session. Scenario can store or read data from session. Data is saved in session with key/value pairs, where key is variable name. Variables are stored in session in three ways: using feeders (this is explained later in current post), using saveAs() method and session API. More details on session API can be found in Gatling Session API page.

Manipulating session through API is kind of tricky. Gatling documentation is vague about it. Bellow is shown a code where session variable is extracted first as String and then converted to Int with: var numberOfProducts = session(“numberOfProducts”).as[String].toInt. On next step some manipulation is done with this variable, in current case a random product id from 1 to “numberOfProducts” to is picked. At last a new variable is saved in session with session.set(“productId”, productId). It is important that this is the last line of session manipulation code block done in first exec(). This is the return statement of the code block. In other words new Session object with saved “productId” in it is returned. If on the last line is just “session” as stated in the docs, then old, unmodified session object is returned without variable being added.

Sessions as most of the objects in Gatling and in Scala are immutable. This is designed for thread safety. So adding variable to session actually creates new object. This is why newly added session variable cannot be used in the same exec() block, but have to be used on next one, as in same block variable is yet not accessible. See code bellow in second exec() “productId” is already available and can be used in get().

private val reqOpenProduct = exec(session => {
	var numberOfProducts = session("numberOfProducts").as[String].toInt
	var productId = Random.nextInt(numberOfProducts) + 1
	session.set("productId", productId)
}).exec(http("Open Product")
	.get("/products?action=details&id=${productId}")
	.check(regex("This is 'Product ${productId} name' details page."))
)

Same logic being explained above is implemented in next code fragment. The bellow example shows usage of session variable saved in previous exec() fragment. Count of persons and List with ids are being saved by saveAs() method. List is extracted from session and random index of it has been accessed, so random person is being selected. This is again saved into session as “person_id”. In third exec() statement “session” object is just printed to output for debug purposes.

private val reqGetAll = exec(http("Get All Persons")
	.get("/person/all")
	.check(regex("\"firstName\":\"(.*?)\"").count.greaterThan(1).saveAs("count"))
	.check(regex("\\[").count.is(1))
	.check(regex("\"id\":([\\d]{1,6})").findAll.saveAs("person_ids"))
).exec(session => {
	val count = session("count").as[Int]
	val personIds = session("person_ids").as[List[Int]]
	val personId = personIds(Random.nextInt(count)).toString.toInt
	session.set("person_id", personId)
}).exec(session => {
	println(session)
	session
})

Standard CSV feeder

Feeder is a way to generate unique data for each virtual user. This how tests are made realistic. Bellow is a way to read data from CSV file. First line of the CSV file is the header which is saved to session as variable name. In current example CSV has only one column, but it is possible to have CSV file with several columns. circular means that if file end is reached feeder will start from the beginning. random means elements are taken in random order. More about feeders can be found in Gatling Feeders page.

private val csvFeeder = csv("search_terms.csv").circular.random

Create custom feeder

Feeder actually is Iterator[Map[String, T]], so you can do your own feeders. Bellow is shown code where some unique ids are read from file and converted to List[String] with Source .fromInputStream(getClass.getResourceAsStream(“/account_ids.txt”)) .getLines().toList. This list is used in buildFeeder() method to access random element from it. Finally Iterator.continually(buildFeeder(uniqueIds)) creates infinite length iterator.

private val uniqueIds: List[String] = Source
	.fromInputStream(getClass.getResourceAsStream("/account_ids.txt"))
	.getLines().toList

private val feedSearchTerms = Iterator.continually(buildFeeder(uniqueIds))

private def buildFeeder(dataList: List[String]): Map[String, Any] = {
	Map(
		"id" -> (Random.nextInt(100) + 1),
		"first_name" -> Random.alphanumeric.take(5).mkString,
		"last_name" -> Random.alphanumeric.take(5).mkString,
		"email" -> Random.alphanumeric.take(5).mkString.concat("@na.na"),
		"unique_id" -> dataList(Random.nextInt(dataList.size))
	)
}

Current business case doesn’t make much sense to have custom feeder with values from file, just Map() generator is enough. But lets imagine a case where you search for hotel by unique id and some date in the future. Hard coding date in CSV file is not a wise solution, you will want to be always in the future. Also making different combinations from hotelId, start and end dates is not possible to be maintained in a file. The best solution is to have file with hotel ids and dates to be dynamically generated as shown in buildFeeder() method.

Create unified scenarios

Scenario is created from HTTP requests. This is why it is good to have each HTTP request as a separate object so you can reuse them in different scenarios. In order to unify scenario creation there is special method. It takes scenario name, feeder and list of requests and returns a scenario object. Method checks if scenario is supposed to be repeated several times and uses repeat() method. Else scenarios is repeated forever(). In both cases there is constant pause time introduced between requests with pause().

def createScenario(name: String, 
					feed: FeederBuilder[_],
					chains: ChainBuilder*): ScenarioBuilder = {
	if (Constants.repeatTimes > 0) {
		scenario(name).feed(feed).repeat(Constants.repeatTimes) {
			exec(chains).pause(Constants.pause)
		}
	} else {
		scenario(name).feed(feed).forever() {
			exec(chains).pause(Constants.pause)
		}
	}
}

In this approach method can be reused from many places avoiding duplication of code.

val scnSearch = Constants.createScenario("Search", csvFeeder,
		reqGoToHome, reqSearchProduct, reqGoToHome)

Conditional scenario execution

It is possible one scenario to have different execution paths based on a condition. This condition is generally a value of a session variable. Branching is done with doIf, doIfElse, doIfEqualsOrElse, etc methods. In current example if this is Save request then additional reqGetPersonAferSave HTTP request is executed. Else additional reqGetPersonAferUpdate HTTP request is executed. In the end there is only one scenario scnSaveAndGet but it can have different execution paths based on “action” session variable.

val scnSaveAndGet = Constants
	.createScenario("Save and get", feedSearchTerms, reqSavePerson)
	.doIfEqualsOrElse("${action}", added) {
		reqGetPersonAferSave
	} {
		reqGetPersonAferUpdate
	}

Only one HTTP protocol

In general case several performance testing simulations can be done for one and the same application. During simulation setUp a HTTP protocol object is needed. Since application is the same HTTP protocol can be one and the same object, so it is possible to define it and reuse it. If changes are needed new HTTP protocol object can be defined or copy of current one can be created and modified.

val httpProtocol = http
	.baseURL(url)
	.check(status.is(successStatus))
	.extraInfoExtractor { extraInfo => List(getExtraInfo(extraInfo)) }

Extract data from HTTP request and response

In order to ease debugging of failures or debugging at all it is possible to extract information from HTTP request and response. Extraction is configured on HTTP protocol level with extraInfoExtractor { extraInfo => List(getExtraInfo(extraInfo)) } as shown above. In order to simplify code processing of extra info object is done in separate method. If debug is enabled or response code is not 200 or Gatling status is KO then request URL, request data and response body are dumped into simulation.log file that resides in results folder. Note that response body is extracted only if there is check on it, otherwise there is NoResponseBody in the output. This is done to improve performance.

private def getExtraInfo(extraInfo: ExtraInfo): String = {
	if (isDebug
		|| extraInfo.response.statusCode.get != successStatus
		|| extraInfo.status.eq(Status.apply("KO"))) {
		",URL:" + extraInfo.request.getUrl +
			" Request: " + extraInfo.request.getStringData +
			" Response: " + extraInfo.response.body.string
	} else {
		""
	}
}

Advanced simulation setUp

It is good idea to keep simulation class clean by defining all objects in external classes or singleton objects. Simulation is mandatory to have setUp() method. It receives comma separated list of scenarios. In order scenario to be valid it should have users injected with inject() method. There are different strategies to inject users. Protocol should also be defined per scenario setup. In this particular example default protocol is used with change to fetch all HTTP resources on a page (JS, CSS, images, etc.) with inferHtmlResources(). Since object are immutable this creates a copy of default HTTP protocol and does not modify the original one. Assertions is a way to verify certain performance KPI it is defined with assertions() method. In this example we should have response time less than 500ms and more than 99% of requests should be successful.

private val rampUpTime: FiniteDuration = 10.seconds

setUp(
	Product.scnSearch.inject(rampUsers(Constants.numberOfUsers) over rampUpTime),
	Product.scnSearchAndOpen.inject(atOnceUsers(Constants.numberOfUsers))
)
	.protocols(Constants.httpProtocol.inferHtmlResources())
	.pauses(constantPauses)
	.maxDuration(Constants.duration)
	.assertions(
		global.responseTime.max.lessThan(Constants.responseTimeMs),
		global.successfulRequests.percent
			.greaterThan(Constants.responseSuccessPercentage)
	)
	.throttle(reachRps(100) in rampUpTime, holdFor(Constants.duration))

Cookies management

Cookie support is enabled by default and then Gatling handles Cookies transparently, just like a browser would. It is possible to add or delete cookies during simulation run. See more details how this is done in Gatling Cookie management page.

Virtual users vs requests per second

Since users is vague metric, but requests per second is metric that most server monitoring tools support it is possible to use this approach. Gatling supports so called throttling: throttle(reachRps(100) in 10.seconds, holdFor(5.minutes)). It is important to put holdFor() method, otherwise Gatling goes to unlimited requests per second and can crash the server. More details on simulation setup can be found on Gatling Simulation setup page.

Conclusion

Keeping Gatling code maintainable and reusable is a good practice to create complex performance scenarios. Gatling API provides wide range of functionalities to support this task. In current post I have shown cases and solution to them which I have encountered in real life projects.

Read more...

Performance testing with Gatling – integration with Maven

Last Updated on by

Post summary: Code samples and explanation how to create performance testing project with Gatling and Maven and run it with Maven plugin.

Current post is part of Performance testing with Gatling series in which Gatling performance testing tool is explained in details.

Code samples are available in GitHub sample-performance-with-gatling repository.

Add Maven dependencies

First step is to create Maven project and add corresponding dependencies to pom.xml file. Only needed is to gatling-charts-highcharts in order to be able to have access to Galling libraries:

<dependencies>
	<dependency>
		<groupId>io.gatling.highcharts</groupId>
		<artifactId>gatling-charts-highcharts</artifactId>
		<version>2.0.0</version>
	</dependency>
</dependencies>

In GitHub code version is configured as property for easy change.

Add Maven plugins

Once dependency to Gatling is added then plugin references should be added. One is for Scala Maven plugin used for compiling/testing/running/documenting Scala code in Maven. Other plugin is Gatling Maven plugin used for running the performance test scenarios:

<build>
	<plugins>
		<plugin>
			<groupId>net.alchim31.maven</groupId>
			<artifactId>scala-maven-plugin</artifactId>
			<version>3.2.2</version>
		</plugin>
		<plugin>
			<groupId>io.gatling</groupId>
			<artifactId>gatling-maven-plugin</artifactId>
			<version>2.0.0</version>
			<configuration>
				<jvmArgs>
					<jvmArg>-Durl=http://localhost:9000</jvmArg>
					<jvmArg>-DnumberOfUsers=10</jvmArg>
					<jvmArg>-DnumberOfRepetitions=1</jvmArg>
					<jvmArg>-DdurationMinutes=1</jvmArg>
					<jvmArg>-DpauseBetweenRequestsMs=3000</jvmArg>
					<jvmArg>-Ddebug=true</jvmArg>
				</jvmArgs>
			</configuration>
		</plugin>
	</plugins>
</build>

Read configurations from Gatling Maven plugin

In order to make it easy to configure several parameters are being passed as jvmArgs, this makes it very easy to run the tests with different configurations. Those are read in code as Java system property:

val numberOfUsers: Int = System.getProperty("numberOfUsers").toInt
val duration: FiniteDuration = System.getProperty("durationMinutes").toInt.minutes
private val url: String = System.getProperty("url")
private val repeatTimes: Int = System.getProperty("numberOfRepetitions").toInt
private val isDebug = System.getProperty("debug").toBoolean

Gatling Maven plugin defaults

By default Gatling Maven plugin uses following default paths, so they do not need to be explicitly provided:

<configuration>
	<configFolder>src/test/resources</configFolder>
	<dataFolder>src/test/resources/data</dataFolder>
	<resultsFolder>target/gatling/results</resultsFolder>
	<bodiesFolder>src/test/resources/bodies</bodiesFolder>
	<simulationsFolder>src/test/scala</simulationsFolder>
</configuration>

Record simulation

Description how to record simulation can be found in Performance testing with Gatling – record and playback post. Once simulation is recorded it can be modified and added to Maven project. More details what a recorded simulation consists of can be found in Performance testing with Gatling – recorded simulation explanation post.

Running simulation

Gatling simulations are run with mvn gatling:execute command. The important part is to provide which is the simulation class to be run. One is to use configuration in pom.xml, other and more flexible is to give it in mvn command: mvn gatling:execute -Dgatling.simulationClass={FULL_PATH_TO_SIMULATION_CLASS}, example is: mvn gatling:execute -Dgatling.simulationClass=com.automationrhapsody.gatling.simulations.original.ProductSimulation

Conslusion

Usage of Gatling with Maven is very convenient and the proper way to do it. Still recorded simulation should be modified before usage. How to modify in order to make it easier to maintain and how to use advanced Gatling features is shown in next post Performance testing with Gatling – advanced usage.

Read more...

Performance testing with Gatling – recorded simulation explanation

Last Updated on by

Post summary: Explanation of automatically generated code of recorded Gatling simulations.

Current post is part of Performance testing with Gatling series in which Gatling performance testing tool is explained in details.

Code samples are available in GitHub sample-performance-with-gatling repository.

Application under test

For current tutorial application from Build a RESTful stub server with Dropwizard post is used. It is pretty simple application. One feature is Products web application where you can search for products, open one and see its details. The other features used in this post is Persons REST service, where you can get or save person via JSON.

Record simulation

Coding simulations from scratch can be difficult and tricky, so it is always a good idea to record the scenario and then modify it. How to record can be found in Performance testing with Gatling – record and playback post. Recording done on application under test for current tutorial produced following simulation files, which can be found in com.automationrhapsody.gatling.simulations.original package of GitHub project. There are two simulations being recorded. ProductSimulation which tests web application and PersonSImulation testing REST service.

ProductSimulation explained

Bellow is recorded code for product simulation:

package com.automationrhapsody.gatling.simulations.original

import io.gatling.core.Predef._
import io.gatling.http.Predef._

class ProductSimulation extends Simulation {

	val httpProtocol = http
		.baseURL("http://localhost:9000")
		.inferHtmlResources()


	val uri1 = "http://localhost:9000/products"

	val scn = scenario("RecordedSimulation")
		.exec(http("request_0")
			.get("/products"))
		.pause(11)
		.exec(http("request_1")
			.get("/products?q=SearchString&action=search-results"))
		.pause(8)
		.exec(http("request_2")
			.get("/products?action=details&id=1"))
		.pause(6)
		.exec(http("request_3")
			.get("/products"))

	setUp(scn.inject(atOnceUsers(1))).protocols(httpProtocol)
}

Simulation is performing following steps:

  • Open /products URI on http://localhost:9000 URL.
  • Wait 11 seconds.
  • Search for “SearchString”.
  • Wait 8 seconds.
  • Open product with id=1 from search results.
  • Wait 6 seconds.
  • Go to home page – /products

With val httpProtocol = http .baseURL(“http://localhost:9000”) .inferHtmlResources() an object of HTTP Protocol is instantiated. URL is configured with baseURL(). All related HTML resources are being captured with any request with inferHtmlResources(). This method allow more precise filtering what resources to be fetched and which skipped. See more in Gatling HTTP Protocol page.

Variable uri1 is defined but is not actually used anywhere, so it is redundant.

Scenario is defined with scenario(“RecordedSimulation”), this method accepts name of the scenario, “RecordedSimulation” in current case. Scenario is a building block of a simulation. One simulation should have at least one scenario. See more about scenarios on Gatling Scenario page.

With exec() method are added actual actions to get executed. In most of the cases action is an HTTP GET or POST request. In current example GET request is done with http(“request_0”) .get(“/products”), where “request_0” is the name of the HTTP Request. Name is used to identify request in results file. So it is good to have unique name for different requests. The “/products” is the URI GET request will open. See more about HTTP requests on Gatling HTTP Request page.

Once scenario and protocol are defined those need to be assembled into a Simulation. Simulation class should extend Gatling’s io.gatling.core.Simulation class. This gives access to setUp() method which is configuring the simulation. setUp method takes a scenario with injected users in it scn.inject(atOnceUsers(1)). In this case one used is injected at simulation start. There are different inject patterns that can be used. More about simulations setup can be found in Gatling Simulation setup page.

PersonSimulation explained

Bellow is recorded code for person simulation:

package com.automationrhapsody.gatling.simulations.original

import io.gatling.core.Predef._
import io.gatling.http.Predef._

class PersonSimulation extends Simulation {

	val httpProtocol = http
		.baseURL("http://localhost:9000")
		.inferHtmlResources()

	val headers_0 = Map(
		"Accept" -> "text/html,application/xhtml+xml,application/xml",
		"Upgrade-Insecure-Requests" -> "1")

	val headers_1 = Map(
		"Origin" -> "chrome-extension://fhbjgbiflinjbdggehcddcbncdddomop",
		"Postman-Token" -> "9577054e-c4a3-117f-74ab-e84a2be473e0")

	val headers_2 = Map(
		"Origin" -> "chrome-extension://fhbjgbiflinjbdggehcddcbncdddomop",
		"Postman-Token" -> "639b36ea-aff3-1b85-618e-c696734afc6e")

	val uri1 = "http://localhost:9000/person"

	val scn = scenario("RecordedSimulation")
		.exec(http("request_0")
			.get("/person/all")
			.headers(headers_0))
		.pause(9)
		.exec(http("request_1")
			.post("/person/save")
			.headers(headers_1)
			.body(RawFileBody("RecordedSimulation_0001_request.txt")))
		.pause(3)
		.exec(http("request_2")
			.post("/person/save")
			.headers(headers_2)
			.body(RawFileBody("RecordedSimulation_0002_request.txt")))

	setUp(scn.inject(atOnceUsers(1))).protocols(httpProtocol)
}

In short scenario is following:

  • Invoke /person/all REST service on on http://localhost:9000 URL.
  • Wait 9 seconds.
  • Save person by POST request to /person/save and RecordedSimulation_0001_request.txt JSON body.
  • Wait 3 seconds.
  • Save again person by POST request to /person/save and RecordedSimulation_0002_request.txt JSON body.

Most of the code here is similar as the one in PersonSimulation, so will not go over it again. Difference is the http(“request_1”) .post(“/person/save”) .headers(headers_1) .body(RawFileBody(“RecordedSimulation_0001_request.txt”)) code. It creates HTTP request with name “request_1”. Here request is POST to “/person/save” URI. POST data is put in the body by body() method, it loads “RecordedSimulation_0001_request.txt” file by reading it directly with RawFileBody() method. In many cases this is not convenient at all, it should be possible to parameterise the request and fill it with test data. This is done with ELFileBody() method.

If you have paid attention to all the readings here and to GitHub project you may have noticed that Gatling Maven plugin defaults say: src/test/resources/bodies, but request is actually in src/test/resources folder of the project. Yes, every project is susceptible to bugs.

Conclusion

Recording scenario is a good way to get started but those needs to be refactored for efficiency and better maintenance. In order to be able to modify first step is to understand what has been recorded. Once recordings are done those will be incorporated in Maven build. This is shown in Performance testing with Gatling – integration with Maven and Performance testing with Gatling – advanced usage posts.

Read more...

Performance testing with Gatling – Scala fundamentals

Last Updated on by

Post summary: Tutorial that covers basic Scala functionalities that may be needed during Gatling automation.

Current post is part of Performance testing with Gatling series in which Gatling performance testing tool is explained in details.

You need to have basic Java knowledge as this tutorial in most of the cases compares Scala with Java.

General concepts

In order to use Scala its compiler needs to be installed from Scala home page. Scala source code is compiled to Java Byte Code and is run on Java Virtual Machine.

Scala is object oriented functional programming language. Everything in Scala is an object. There are no primitive types as in Java, those are represented by objects. Even functions are also objects.

There is very good interoperability with Java and Java code can be used inside Scala. Java object from Java classes can be created, also static methods in Java classes can be called.

Syntax

Scala syntax is pretty much the same as in Java. Although Scala is statically typed (checks are done at compile time) in most of the cases you do not need to explicitly specify variable type, Scala compiler knows it.

Scala is case-sensitive, class names are CamelCase with first letter being capital, method names are also camel case starting with a lower case letter.

Semicolon “;” is not mandatory at the end of the line is it has only one expression. In case of more expressions on one line then is mandatory to separate each expression with semicolon.

Classes and packages

Class file name should be with the same name as class itself.

Import all classes from package is done with underscore:

import io.gatling.core.Predef._

Import of several classes from a package is done with curly brackets:

import org.joda.time.format.{DateTimeFormat, DateTimeFormatter}

Data types

As stated above everything is Scala is object. There are no primitive types. Those are represented by objects:

  • Byte – 8 bit signed value. Range from -128 to 127
  • Short – 16 bit signed value. Range -32768 to 32767
  • Int – 32 bit signed value. Range -2147483648 to 2147483647
  • Long – 64 bit signed value. -9223372036854775808 to 9223372036854775807
  • Float – 32 bit IEEE 754 single-precision float
  • Double – 64 bit IEEE 754 double-precision float
  • Char – 16 bit unsigned Unicode character. Range from U+0000 to U+FFFF
  • String – a sequence of Chars
  • Boolean – either the literal true or the literal false
  • Unit – corresponds to no value
  • Null – null or empty reference
  • Nothing – the subtype of every other type; includes no values
  • Any – the supertype of any type; any object is of type Any
  • AnyRef – the supertype of any reference type

Strings and Arrays

Strings and arrays are very similar to Java ones. In Scala is possible to define multi-line string literal. This is done with three quotes: “””This is text

split on two lines”””

Variables

Variable declaration is done with following format:

val or val VariableName : DataType [= Initial Value]

Example is: var answer : Int = 42. This is full declaration. In most cases you do not need to provide data type, so above can be shortened to: var answer = 42.

With var you define a variable that is going to change its value. On the other hand val keyword is used for defining variables that will never change, constants, like final in Java.

Access modifiers

Access modifiers are public, private and protected. There is no explicit keyword public though. If no modifier is used then access level is considered public.

private and protected can be defined for specific scope.

private[com.automationrhpasody.gatling]

In example above field, method or class that this modifier is applied to is considered private for all the world, except for classes in package com.automationrhpasody.gatling. Scope can be single class or singleton object (more about those will follow).

Operators

Operators are very similar to Java. Those are:

  • Arithmetic Operators (+, -, *, /, %)
  • Relational Operators (==, !=, >, <, >=, <=)
  • Logical Operators (&&, |, !)
  • Bitwise Operators (&, |, ^, ~, <<, >>, >>>)
  • Assignment Operators (=, +=, -=, *=, /=, %=, <<=, >>=, &=, ^=, |=)

Unlike Java there are no ++ and — operators. This is because everything in Scala is object and default data types are immutable objects. So modifications on current object are not possible, new object is created instead, so it is not possible to have ++ and — operations.

Conditional statements

Conditional statement is if/else same as in Java:

if (condition) {
	statement
}

if (condition) {
	statement1
} else {
	statement2
}

if (condition1) {
	statement1
} else if (condition2) {
	statement2
} else {
	statement3
}

Loop statements

Loop statements are for, while, do/while. For statement is very specific, the easiest way to use it is with Ranges:

for (i <- 1 until 10) {
	println("i=" + i)
}

The code above will print values from 1 to 9. Operator <- is called generator as it generating the individual values from the range. 1 until 10 is the actual range. This is the number from 1 to 9, 10 is not included. If you want the last value included use to: 1 to 10.

It is possible to put some conditional statement in the for loop with if clause:

for (i <- 1 until 10; if i >= 3 && i <= 6) {
	println("i=" + i)
}

The code above will print values 3, 4, 5 and 6. Only those are >= 3 and <= 6 from the whole range. Nested for loops are pretty easy in Scala and not that apparent, so it is easy to get into performance issues: [scala] for (i <- 1 until 5; j <- 1 to 3) { println("i=" + i) println("j=" + j) } [/scala] The code above is equal to Java code: [java] for (int i = 0; i < 5; i++) { for (int j = 0; j <= 3; j++) { System.out.println("i=" + i); System.out.println("j=" + j); } } [/java] For loop can also be used with collections: [scala] val daysOfWeek = List("Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun") for (str <- daysOfWeek) { println("day=" + str); } [/scala] You can also iterate Java collections, but first they need to be converted by classes in scala.collection.JavaConversions package. Bellow is example iterating Java’s System Properties:

import scala.collection.JavaConversions._

for (key <- System.getProperties.keySet().iterator.toIterator) {
	println("Key=" + key + ", Value=" + System.getProperty(key.toString))
}

Loop statements while and do/while as as in Java:

while (condition) {
	statement
}

do {
	statement
} while (condition)

Methods and functions

Scala has both functions and methods. This is a group of statements and conditions that perform a task and can return a result. Difference between those is that method can be defined only inside a class. Function can be defined anywhere in the code. This is complete object that can be assigned to variable. Functions and method names in Scala can contain special characters such like +, -, &, ~, etc.

Function definition is:

def functionName ([list of parameters]) : [return type] = {
	function body
	[return] [expr]
}

Data in [] are optional. Return type is any valid Scala type. If nothing is to be returned then Unit is returned, this is as void methods in Java. As you can notice even return statement in the end is not mandatory and can be omitted, then function will return the statement that comes last.

def sum(a: Int, b: Int): Int = {
	a + b
}

Function/method above sums two Integer values and returns the result of the sum.

Function is called the same way as in Java:

[object.]functionName([list of parameters])

Scala is function based language, so there are many many things that can be done with functions. More you can read on Scala functions in Tutorialspoint.

Collections

Collection is a group of objects. Scala API has rich set of collections. By default collections in Scala are immutable. This means current collection object cannot be changed, if you do some change on a collection this results in creation of new collection with desired changes applied in it. This is made for thread safety. There are also mutable collections. They can be found in scala.collection.mutable package.

  • Lists – lists are very similar to arrays, you have elements in sequential order that can be accessed.
  • Sets – collection of unique elements, there are no duplicates.
  • Maps – collection of key/value pairs. Values are retrieved based on their unique key.
  • Tuples – combines several elements together so they can be considered one object.
  • Iterators – not actually a collection, but a way to access elements from a collection one by one.

More about Scala collections can be found in Scala collections in Tutorialspoint.

Classes, objects

Class is a blueprint for objects. Class is like a cookie cutter. Objects are the cookies. Objects are created with keyword new. Class name is a class constructor taking different arguments. You can pass parameters to it. Class can have several constructors. Restriction is that each constructor should call on its first line some other constructor. Eventually main constructor in class name will get called. Classes can be extended similar to Java.

class Car(isStarted: Boolean) {
	var _isStarted: Boolean = isStarted
	var _speed: Int = 0

	def this() = this(true)

	def start(): Unit = {
		_isStarted = true
		println("Car is started: " + _isStarted)
	}

	def drive(speed: Int): Unit = {
		_speed = speed
		if (_isStarted) {
			println("Car moving with speed: " + _speed)
		} else {
			println("Car is not started!")
		}
	}
}

Singleton objects

In Scala there is no definition of static methods or fields. In order to accomplish similar functionality you can use singleton objects, classes with only one instance defined with object keyword.

object UseThatCar {
	def main(args: Array[String]) {
		val car1 = new Car(false)
		car1.drive(50)

		val car2 = new Car()
		car2.drive(45)
	}
}

Resources

I do not tend to be Scala expert. I know little but enough to make Gatling performance testing. So I have used other network resources to build this post. Very good tutorial is Scala in Tutorialspoint. Another interesting post is The 10 Most Annoying Things Coming Back to Java After Some Days of Scala.

Conclusion

People that have worked with Scala really love it. It is made for performance and scalability. Because everything is object and default types are immutable objects Scala is much more thread safe than Java. Functions can be defined anywhere and do everything you want, so you can do almost everything with just functions if you like. Although it is that good Scala is compiled to Byte Code and run on Java Virtual Machine, so limitations applicable to JVM are applicable to Scala executable code. No matter it you like it or not, you have to learn basics of Scala as Gatling is written in Scala and in order to do performance testing with it you have to know Scala fundamentals.

Read more...

Performance testing with Gatling – record and playback

Last Updated on by

Post summary: How to record a simulation with Gatling recorder and play it back.

Current post is part of Performance testing with Gatling series in which Gatling performance testing tool is explained in details.

Run the recorder

Once Gatling is downloaded recorder can be run with “GATLING_HOME\bin\recorder.bat”. Recorder has two working modes: HTTP Proxy and HAR Converter.

Gatling-recorder-HTTP

Configure browser proxy

Network traffic should be redirected through Gatling Recorder in order to be captured in HTTP Proxy mode. By default recorder works on 8000 port, but this is configurable. If a web application is being tested then browser should be configured to work through the Gatling Recorder proxy. Firefox is configured from Tools -> Options -> Advanced -> Network -> Settings… -> Manual proxy configurations: -> localhost with Port: 8000, Use this proxy server for all protocols.

Gatling-set-proxy-Firefox

Microsoft Edge browser has also specific configurations for setting a proxy: Settings -> Network & Internet -> Proxy -> Manual proxy setup.

Gatling-set-system-proxy

Configure system proxy

If network traffic that is going to be recorded is not browser based, e.g. REST or SOAP call, then system-wise proxy should be configured. For Windows this is done through Control Panel -> Internet Options-> Connections -> LAN Settings -> Use a proxy server for your LAN. This configuration forces applications network traffic to go through configured proxy. Same configuration is done in order to configure proxy for Chrome, Opera and Internet Explorer browsers.

Use Gatling Recorder’s HTTP Proxy

Once proxy is configured then “Start” button runs the Gatling Recorder proxy and opens new window that shows all requests being captured. “Stop & Save” button stops the proxy and saves all requests that went trough into a Gatling simulation file. Image bellow is screenshot of recording of testing RESTful stub server built in Build a RESTful stub server with Dropwizard post which will be used for testing purposes in these tutorial series.

Gatling-recorded

HTTPS and Gatling Recorder

HTTPS is HTTP over SSL or TLS security layer. It is designed to bring security in normal HTTP communication. This security is guaranteed with server being issues certificate issued by certification authority. Gatling is intercepting the traffic between server and client (browser) hence is considered intruder into safe HTTPS communications. There are several mechanisms provided by recorder to handle this. Those are handled in HTTPS modes configuration. The easiest to use is “Self-signed Certificate”. In this mode Gatling is using certificate which is not issued for web application being tested, hence browsers are recognising it as invalid. Browsers gives warning that certificate is invalid and asks for user’s permission to continue. Beware: in normal daily internet browsing such warning is a sign that something is wrong, your HTTPS connection might be sniffed, so be careful what data you provide in such cases. Some sites are configured in a manner that if certificate is invalid you are unable to proceed. Here is how Firefox react in both cases. When there is possibility to continue there is “Add Exception…” button.

Gatling-Firefox-SSL-error

Other options to handle certificate problem is “Provided Keystore” and “Certificate Authority” HTTPS mode. For both valid certificate should be issued for domain under test. More details how to do this can be found Gatling Recorder page.

In case traffic that has to be captured is not browser based tools that are used to simulate requests should provide support for handling missing valid certificates in case of “Self-signed Certificate”. If you custom code that sends SOAP is being written then Send SOAP request over HTTPS without valid certificates post describes how to work without valid certificates. This can be applied also in case of RESTful HTTPS call.

Use Gatling Recorder’s HAR Converter

Generating and handling SSL certificates could be painful process. Before diving into it other option that is good to be considered is using Gatling Recorder in HAR Converter mode. In order to do this all network traffic should be recorded as HTTP Archive – HAR. This can easily be done with Chrome DevTools plugin that is activated with F12 keyboard key. Remember to select “Preserve log” check box before starting to record test scenario. Once scenario is recorded it can be exported with right mouse click and then “Save as HAR with content”.

Gatling-capture-traffic-HAR

Beware: sensitive data such as passwords are also exported as plain text in HAR archive. Once traffic is being recorder and exported it then gets converted to Gatling simulation by Gatling Recorder. In order to exclude not important requests, e.g. images, CSS, JS, call to other domains there is Blacklist that accepts Java regular expressions. It is possible to use default list by clicking “No static resource” button. There is also Whitelist that can accept only needed requests.

Gatling-recorder-HAR

Running recorded scenario

Gatling Recorder saves scenarios in directory configured in “Output folder*”. By default it uses “GATLING_HOME\user-files\simulations” folder. Simulations are run with “GATLING_HOME\bin\gatling.bat”. Once started is looks default simulations folder and gives a list of all simulations. User selects simulation by number in the list and then gives short description for this run. Simulations can be changed before run in order to configure different number of users as it is 1 by default. If simulations are recorded in different that default folder then runner cannot find them. In such case one option is to move them to “GATLING_HOME\user-files\simulations” or:

Use non-default simulations folder

In order to use different than default simulation’s folder then this should be configured in “GATLING_HOME\conf\gatling.conf” file. Following configuration elements hierarchy: gatling -> core -> directory -> simulations = “C:\\Gatling\\simulations”.

Conclusion

Gatling recorder is powerful and provides various ways to record a scenario. Either by capturing network traffic in HTTP Proxy mode or by importing already captured network traffic in HAR Converter mode.

Read more...

Performance testing with Gatling

Last Updated on by

Post summary: Tutorial how to use Gatling and do successful performance testing with it.

This is first of series of posts designed to give complete overview of Gatling performance testing tool. Other post in the series are:

Performance testing

Performance testing is a way to identify how application behaves in case of high user load. In this post “performance testing” is used as a collective term but it actually has different aspects which are described in Performance, Load, Stress and Soak testing post. The essence and best practices of performance testing are described into How to do proper performance testing post. Current post is about how to do it with Gatling

Gatling

Gatling is very powerful tool. Build on top of Akka it enables thousands of virtual users on a single machine. Akka has message driven architecture and this overrides the JVM limitation of handling many threads. Virtual users are not threads but messages. Tests are written in Scala, which makes scenarios creation and maintenance more complex.

Gatling Recorder

For easy scenario creation Gatling provide very good recorder. It works as a proxy capturing all traffic and converting it into Gatling scenario. Detailed explanation how to record scenario can be found in Performance testing with Gatling – record and playback post.

Run simulation

Once simulation is recorded it can be changed with proper values, user count, etc and run. How to run a simulation can be found in the end of Performance testing with Gatling – record and playback post.

Gatling terminology

“Simulation” is the actual test. It is a Scala class that extends Gatling’s io.gatling.core.scenario.Simulation class. Simulation has a HTTP Protocol object instantiated and configured with proper values as URL, request header parameters, authentication, caching, etc. Simulation has one or more “Scenario”. Scenario is a series of HTTP Requests with different action (POST/GET) and request parameters. Scenario is the actual user execution path. It is configured with load users count and ramp up pattern. This is done in the Simulation’s “setUp” method. Several scenarios can form one simulation. There are other elements like Feeders that create input data and Checks that are used to validate responses. Those will be discussed in separate post.

REST and SOAP

REST and SOAP are also easily supported by Gatling since in they are very nature they are just a HTTP requests. SOAP is HTTP POST request with XML data put into request body. It is possible to have some special HTTP Headers in the request but in general case this is it. REST is either HTTP GET request with key/value params in the URI or HTTP POST request with JSON or XML data into request body. There are also HTTP Header parameters in the request to indicate the data type being sent, etc.

Scala

Scala is object oriented language and functional programming language, providing best of both worlds. Everything in Scala is object, there are no primitive data types like int, long, char, etc in Java. More simple Scala tutorial can be found in Performance testing with Gatling – Scala fundamentals post.

Advanced Gatling

In order to properly edit simulation it should be included in a project and imported in some IDE. Gatling provide a Gatling Maven plugin. There are more plugins to be used they can be found on Gatling extensions page. Simulation can be recorded with recorder and further processed as a Maven project. Information with examples how this can be done is shown in Performance testing with Gatling – integration with Maven and Performance testing with Gatling – advanced usage posts.

Conclusion

Gatling is very good performance testing tool. It is capable of creating immense amount of traffic from a single node. It requires basic knowledge in Scala which is his main disadvantage. Java code can be directly used in Scala classes. Advance usage is from a Maven project which makes it more easy to use and maintain scenarios.

Read more...

Performance, Load, Stress and Soak testing

Last Updated on by

Post summary: Performance, Load, Stress and Soak testing are different aspects of one goal – proving that application will function correctly with large amount of users.

Previously I have written for non-functionally testing the application in conditions of large amount of users in How to do proper performance testing post. There I’m using only one term performance testing. If we have to be precise there are several different types of testing that can be done to achieve the goal of sustaining large amount of users.

Performance testing

Testing the system to find out how fast is the system. Create a benchmark of system response times and stability under particular user load. Response time should be small enough to keep users satisfied.

Load testing

Testing how the system performs when it is loaded with its expected amount of users. Load can be slightly increased to measure if and how performance degrades. Load and performance testing are tied together. System performance depends on the load applied to it. Load testing should prove that in case of expected and peak users load system performs close to benchmarks measured with small load.

Stress testing

Testing of the system beyond its normal expected amount of users to observe its behaviour. Sometimes system is loaded until its crash. The idea behind this testing is to understand how system handles errors and data when it is highly loaded, is data preserved correctly, what load can crash the system, what happens when the system crashes.

Soak testing

This is kind of underestimated but it is rather important. Soak testing is to test the system with expected or little more than expected load for a long amount of time. The idea behind that is system may respond fast during short tests but actually to hide some memory leak which will become obvious after long amount of time.

Knowledge is power

Knowing the problems helps to prepare against them. Procedures can be prepared and followed to avoid system crash. In case there is a module identified to be slow but important for business it can be made configurable and can be turned down in case of higher load. In case users count have reached critical level that could endanger the system, support can reject some users. In case of memory leaks, support can restart the system on regular intervals in time of low load to avoid crash. All those and many more can be done only if we know the system.

Conclusion

There are different techniques to prove that system can handle amount of users expected by business. I like the term performance testing and use it to combine all the types of testing above. It is not that important to know the precise definition of the terms than to know what is good to be done in order to prove system can handle large amount of users, or to identify the bottlenecks in case it cannot.

Read more...

Code coverage with JaCoCo offline instrumentation with Maven

Last Updated on by

Post summary: Tutorial how to do code coverage with offline instrumentation with JaCoCo and Maven.

Offline instrumentation

Code coverage of manual or automated tests with JaCoCo post describes how to do code coverage with JaCoCo. This is applicable in many of the cases. Still there could be a case where application under test does not support Java agents. In this case JaCoCo offers offline instrumentation of the code. Once instrumented code can be run and coverage to be measured. This post describes how to do it.

JaCoCo for Maven

JaCoCo Maven plugin is discussed in Automated code coverage of unit tests with JaCoCo and Maven post. In order to get code instrumented “instrument” task should be added to Maven:

<properties>
	<jacoco.skip.instrument>true</jacoco.skip.instrument>
</properties>
<build>
	<plugins>
		<plugin>
			<groupId>org.jacoco</groupId>
			<artifactId>jacoco-maven-plugin</artifactId>
			<version>0.7.4.201502262128</version>
			<executions>
				<execution>
					<id>jacoco-instrument</id>
					<phase>test</phase>
					<goals>
						<goal>instrument</goal>
					</goals>
					<configuration>
						<skip>${jacoco.skip.instrument}</skip>
					</configuration>
				</execution>
			</executions>
		</plugin>
	</plugins>
</build>

In current example this task will be executed when “mvn test” is called. It can be configured to be called on “package” or “install” by changing the “” element.

Make it configurable

Instrumentation MUST not be done on every build. You do not want to release instrumented code, first because this is bad practice and second code will not run unless jacocoagent.jar is in classpath. This is why instrumentation should be disabled by default with jacoco.skip.instrument=true pom.xml property, which can be overridden when needed with “mvn clean test -Djacoco.skip.instrument=false” command. Other option is separate pom-offline.xml file and build with it when needed.

Get sample application

Current post uses sample application first introduced in Build a RESTful stub server with Dropwizard post. It can be found in GitHub sample-dropwizard-rest-stub repository. For current tutorial it has been downloaded to C:\sample-dropwizard-rest-stub. This application gets packaged to a single JAR file by “mvn clean package”. If instrumentation gets put in “package” phase then it is not working, as packaging happens before instrumentation. This is why “test” phase is the correct for current example, as “package” includes test by default.

Instrument the code

Once application is downloaded it can be built with instrumentation with “mvn clean package -Djacoco.skip.instrument=false” command. It can be easily check if given class has been instrumented by opening it with some kind of decompiler. Image bellow shows instrumented class on the right hand side vs non-instrumented in the left hand side.

JaCoCo-offline

Run it with JaCoCo agent in the class path

If not instrumented sample application is started with “java -jar target/sample-dropwizard-rest-stub-1.0-SNAPSHOT.jar server config.yml” command. In case of instrumented code this command will give exception:

Exception in thread “main” java.lang.NoClassDefFoundError: org/jacoco/agent/rt/internal_773e439/Offline

This is because jacocoagent.jar is not in the classpath.

Adding JaCoCo agent in class path varies from case to case. In this particular tutorial application is a single JAR run by “java -jar” command. In order to add something in classpath “java -cp” command should be used. Problem is both “-jar” and “-cp” are mutually exclusive. Only way to do it is with following command:

java -Djacoco-agent.output=tcpserver -cp C:\JaCoCo\jacocoagent.jar;target/sample-dropwizard-rest-stub-1.0-SNAPSHOT.jar com.automationrhapsody.reststub.RestStubApp server config.yml

Where -Djacoco-agent.output=tcpserver is configuration to make JaCoCo agent report on TCP port. More about JaCoCo Offline settings here. “C:\JaCoCo\jacocoagent.jar” is the location of the JaCoCo agent JAR file. “com.automationrhapsody.reststub.RestStubApp” is main method to be run from target/sample-dropwizard-rest-stub-1.0-SNAPSHOT.jar file.

Test

Now when we have the application running is time to run all tests we have both automation and manual. For manual it is important to be documented scenario which is reproducible on each regression testing, not just some random clicking. The idea is that we want to measure what coverage our tests do.

Import coverage results

In order to import results Eclipse with installed JaCoCo plugin from market place is needed. See Code coverage of manual or automated tests with JaCoCo post for more details how to install plugin.

Open Eclipse and import C:\sample-dropwizard-rest-stub project as Maven one.

Import the results into Eclipse. This is done from File -> Import -> Coverage Session -> select Agent address radio button but leave defaults -> enter some name and select code under test.

JaCoCo-import

Once imported results can be seen and code gets highlighted.

In case no results are imported delete “target\classes” folder and rebuild with “mvn compile”.

Export to HTML and analyse

See Code coverage of manual or automated tests with JaCoCo how to export and analyse.

Conclusion

Although very rare to happen offline instrumentation is a way to measure code coverage with JaCoCo.

Read more...

Automated code coverage of unit tests with JaCoCo and Maven

Last Updated on by

Post summary: Tutorial how to setup code coverage with JaCoCo on unit tests to be done on each Maven build.

Code coverage

There are two main streamlines in code coverage. One is running code coverage on each build measuring unit tests coverage. Once configured this needs no manual intervention. Depending on the tools there is even an option to fail build if code coverage doesn’t reach desired threshold. Current post is designated to this aspect. Other is running code coverage on automated or even manual functional tests scenarios. Latter is described in Code coverage of manual or automated tests with JaCoCo post.

Unit tests code coverage

Theory described in What about code coverage post is applicable for unit tests code coverage, but the real benefit of unit tests code coverage is:

  • Unit tests code coverage can be automated on every build
  • Build can be configured to fail if specific threshold is not met

JaCoCo for Maven

There is JaCoCo plugin that is used with Maven builds. More details and what goals can be accomplished with in can be seen in JaCoCo Maven plugin page. The very minimum to make it work is to setup “prepare-agent” and “report” goals. Report is good to be called during “test” Maven task. This is done with test instruction. You can define it on other tasks, like install or package, however code coverage is done for tests. XML block to be added to pom.xml file is:

<plugin>
	<groupId>org.jacoco</groupId>
	<artifactId>jacoco-maven-plugin</artifactId>
	<version>0.7.4.201502262128</version>
	<executions>
		<execution>
			<id>jacoco-initialize</id>
			<goals>
				<goal>prepare-agent</goal>
			</goals>
		</execution>
		<execution>
			<id>jacoco-report</id>
			<phase>test</phase>
			<goals>
				<goal>report</goal>
			</goals>
		</execution>
	</executions>
</plugin>

Once this is configured it can be run with “mvn clean test” command. Once successfully build JaCoCo report can be found in “/target/site/jacoco/index.html” file. Similar report can be found in HTML JaCoCo report.

Add coverage thresholds

Just adding unit tests code coverage report is good but can be rather improved. Good practice is to add code coverage thresholds. If predefined code coverage percentage is not reached build will fail. This practice could have a negative effect of putting unit tests just for the sake of code coverage, but then again it is up to the development team to keep the good quality. Adding thresholds is done with “check” Maven task:

<execution>
	<id>jacoco-check</id>
	<phase>test</phase>
	<goals>
		<goal>check</goal>
	</goals>
	<configuration>
		<rules>
			<rule implementation="org.jacoco.maven.RuleConfiguration">
				<element>BUNDLE</element>
				<limits>
					<limit implementation="org.jacoco.report.check.Limit">
						<counter>INSTRUCTION</counter>
						<value>COVEREDRATIO</value>
						<minimum>0.60</minimum>
					</limit>
				</limits>
			</rule>
		</rules>
	</configuration>
</execution>

“check” task should be added along with “prepare-agent”. “report” is not mandatory but could also be added in order to inspect where code coverage is not enough. Note that “implementation” attribute is mandatory only for Maven 2. If Maven 3 is used then attributes can be removed.

JaCoCo check rules

In order “check” task to work is should be added at least one “goal” element as shown above. Rule is defined for particular scope. Available scopes are: BUNDLE, PACKAGE, CLASS, SOURCEFILE or METHOD. More details can be found in JaCoCo check Maven task documentation. In current example rule is for BUNDLE, which means whole code under analysis. PACKAGE is the far I would go. Even with it, there could be unpleasant surprises like an utility packages or POJO (data object without business logic inside) packages where objects do not have essential business logic but the PACKAGE rule will still require given code coverage for this package. This means you will have to write unit tests just to satisfy the coverage demand.

JaCoCo check limits

Although not mandatory each rule is good to have at least one “limit” element as shown above.

Available limit counters are: INSTRUCTION, LINE, BRANCH, COMPLEXITY, METHOD, CLASS. Those are the values measured in report. Some of them are JaCoCo specific other are accordance with code coverage general theory. See more details on counters in JaCoCo counters page. Check sample report at HTML JaCoCo report to see how counters are displayed.

Available limit values are: TOTALCOUNT, COVEREDCOUNT, MISSEDCOUNT, COVEREDRATIO, MISSEDRATIO. Those are the magnitude values for measuring. COUNT values are bounding with current implementation and cannot be referred to some industry standards. This is why RATIO values are much more suitable.

Actual measuring value is set in “minimum” or “maximum” elements. Minimum is generally used with COVERED values, maximum with MISSED values. Note that in case of RATIO this should be double value less than 1, e.g. 0.60 in example above means 60%.

With given counters and values there could be lots of combinations. The very minimum is to use INSTRUCTION with COVEREDRATIO as shown in example above. Still if you want to be really precise several limits with different counters can be used. Bellow is an example for Maven 3 where defining that every class should have been covered in init tests:

<limit>
	<counter>CLASS</counter>
	<value>MISSEDCOUNT</value>
	<maximum>0</maximum>
</limit>

Configurations are good practice

Hard-coding is never a good practice anywhere. Example above have hard-coded value of 60% instruction code coverage, otherwise build will fail. This is not a proper way to do it. Proper way is to define a property and then use it. Properties element is defined at a root level:

<properties>
	<jacoco.percentage.instruction>0.60</jacoco.percentage.instruction>
</properties>

...

<limit>
	<counter>INSTRUCTION</counter>
	<value>COVEREDRATIO</value>
	<minimum>${jacoco.percentage.instruction}</minimum>
</limit>

Benefit of property is it can be easily overridden on runtime, just specify new value as system property: “mvn clean test -Djacoco.percentage.instruction=0.20”. In this way there could be general value of 0.60 in pom.xml, but until this is not reached it can be overridden with 0.20.

Experiment with JaCoCo checks

Sample application to experiment with is the one introduced in Build a RESTful stub server with Dropwizard post. It can be found in GitHub sample-dropwizard-rest-stub repository. It has very low amount of code in it and just one unit test with very low code coverage. This gives good opportunities to try different combinations of counters and values to see how exactly JaCoCo works.

Conclusion

Code coverage of unit tests with thresholds is a good practice. This tutorial gives very good introduction how to implement and use them, so apply and use them.

Read more...

Code coverage of manual or automated tests with JaCoCo

Last Updated on by

Post summary: Tutorial how to do code coverage on automated or even manual functional tests with JaCoCo.

Code coverage is a way to check what part of the code your tests are exercising. JaCoCo is a free code coverage library for Java.

Code coverage

There are two main streamlines in code coverage. One is running code coverage on each build measuring unit tests coverage. Once configured this needs no manual intervention. Depending on the tools there is even an option to fail build if code coverage doesn’t reach desired threshold. This is well described in Automated code coverage of unit tests with Maven and JaCoCo post. Other aspect is running code coverage on automated or even manual functional tests scenarios. This post is dedicated to latter. I have already created What about code coverage post to theory of this type of code coverage. Current post is about getting it done in practice.

Idea

Idea is pretty simple. Application is started with a code coverage tool is attached to it, any test are executed and results are gathered. This is it. Having stated it that way it doesn’t sound that bizarre to run code coverage on manual tests. Running it makes sense if only tests are well documented and repeatable scenarios that are usually run on regression testing.

JaCoCo Java agent

Java agent is powerful mechanism providing ability to instrument and change classes at run time. Java agent library is passed as a JVM parameter when running given application with “-javaagent:{path_to_jar}”. JaCoCo tool is implemented as Java agent. More details for Java agents can be found at java.lang.instrument package.

In case application under test does not support pluging agents to JVM then coverage can be measured with offline instrumentation described in Code coverage with JaCoCo offline instrumentation with Maven post.

Restrictions

Some restrictions that has to be taken into consideration:

  • JaCoCo plugin is only for Eclipse IDE, hence it should be used in order to get report
  • Imported execution data must be based on the exact same class files that are also used within the Eclipse IDE, hence application should be run in Eclipse, it is not possible to build it and run it separately as class files will differ
  • Eclipse is not capable of shutting down the JVM, it directly kills it, hence only way to get results is to start JaCoCo agent in “tcpserver” output mode
  • JaCoCo agent version 0.7.4 and Eclipse EclEmma plugin 2.3.2 are used, those are compatible, 0.7.5 introduces change in data format

Install Eclipse plugin

Having stated the restriction it is time to start. Installation is done through Eclipse -> Help -> Eclipse Marketplace… -> search for “jacoco” -> Install -> restart Eclipse.

JaCoCo-install

Run the application

As stated in restrictions in order code coverage to work application should be started in Eclipse. I will use sample application I have introduced in Build a RESTful stub server with Dropwizard post. It can be found in GitHub sample-dropwizard-rest-stub repository. For this tutorial it is checked out to: C:\sample-dropwizard-rest-stub.

Download JaCoCo 0.7.4 agent jar. For this tutorial it is saved to C:\JaCoCo

Project have to imported to Eclipse from File -> Import -> Existing Maven projects. Once imported Run configuration have to be done from Run -> Run Configurations… -> double click Java Application. This opens new window to define configuration. Properties are stated bellow:

  • Name (Main tab): RestStubApp (could be whatever name)
  • Project (Main tab): sample-dropwizard-rest-stub
  • Main class (Main tab): com.automationrhapsody.reststub.RestStubApp
  • Program arguments (Arguments tab): server config.yml
  • VM arguments (Arguments tab): -javaagent:C:\JaCoCo\jacocoagent.jar=output=tcpserver (started in “tcpserver” output mode)
  • Working directory -> Other (Arguments tab): C:\sample-dropwizard-rest-stub

JaCoCo-run

Once configuration is created run it.

Apart from the given sample application it should be possible to run every application in Eclipse. This assumption is made on the fact that developers do need to debug their application, so they will have a way to run it. Important part is to include -javaagent: part in VM arguments section

Test

Now when we have the application running is time to run all tests we have both automation and manual. For manual it is important to be documented scenario which is reproducible on each regression testing, not just some random clicking. The idea is that we want to measure what coverage our tests do.

Import coverage results

After all tests have passed it is time to import the results into Eclipse. This is done from File -> Import -> Coverage Session -> select Agent address radio button but leave defaults -> enter some name and select code under test.

JaCoCo-import

Once imported results can be seen and code gets highlighted.

JaCoCo-results

Export to HTML

Now result can be exported. There are several options: HTML, zipped HTML, XML, CSV or JaCoCo exctution data file. Export is done from: File -> Export -> Coverage Report -> select session and location.

JaCoCo-export

Analyse

Here come the hard part. Code could be quite complex and not that easy to understand. In the current tutorial code is pretty simple. Inspecting HTML JaCoCo report it can be easily noticed that addPerson() method has not been called. This leads to conclusion that one test has been missed – to invoke all persons endpoint. Another finding is that ProductServlet hasn’t been tested with empty product id.

Conclusion

It is pretty easy to measure the code coverage. Whether to do it is another discussion held in What about code coverage post. If there is time it might be beneficial. But do not make code coverage an important KPI as this could lead to aimless test with only one purpose – higher percentage. Code coverage should be done in order to optimise tests and search for gaps.

Read more...

How to do proper performance testing

Last Updated on by

Post summary: Describe what actions are needed in order to make successful performance testing.

Functional testing that system works as per user requirements is a must for every application. But if application is expected to handle large amount of users then doing a performance testing is also important task. Performance testing have different aspect like load, stress, soak. More about them can be found in Performance, Load, Stress and Soak testing post. Those are all incorporated into term “performance testing” in current article. Steps to achieve successful performance testing in short are:

  1. Set proper goals
  2. Choose tools
  3. Try the tools
  4. Implement scenarios
  5. Prepare environments
  6. Run and measure

Setting the goal

This is one of the most important steps before starting any performance initiative. Just making performance for the sake of making performance is worthless and waste of effort. Before starting any activity it should be clear how many users are expected, what is the peak load, what users are doing on the site and many more. This information usually is obtained from business and product owners, but it could be obtained by certain statistical data. After having rough numbers then define what answers performance test should give. Questions could be:

  • Can the system handle 100 simultaneous users with response time less than 1 second and no error?
  • Can the system handle 50 requests/second with response time less than 1.5 seconds for 1 hour and no more than 98% errors?
  • Can system work 2 days with 50 simultaneous users with response time less than 2 seconds?
  • How the system behaves with 1000 users? With 5000 users?
  • When will the system crash?
  • What is the slowest module of the system?

Choosing the tools

Choosing the tool must be done after the estimated load has been define. There are many commercial and non-commercial tools out there. Some can produce huge traffic and cost lots of money, some can produce mediocre traffic and are free. Important criteria of choosing a tool is how many virtual users it can support and can it fulfil performance goal. Another important thing is can QAs be able to work with it and create scenarios. In current post I will mention two open source tools JMeter and Gatling.

JMeter

It is well known and proven tool. It is very easy to work with, no programming skills are needed. No need to spend many words on its benefits, they are many. Problems though are that it has certain limitations on the load it may produce from a single instance. Virtual users are represented as Java thread and JVM is not good on handling too many threads. Good thing is it provides mechanism for adding more hosts that participate in the run and can produce huge load. Management of those machines is needed. Also there are services in the cloud that offer running JMeter test plans and you can scale up there.

Gatling

Very powerful tool. Build on top of Akka it enables thousands of virtual users on a single machine. Akka has message driven architecture and this overrides the JVM limitation of handling many threads. Virtual users are not threads but messages. Disadvantage is that tests are written in Scala, which makes scenarios creation and maintenance more complex.

Try the tools

Do not just rely on marketing data provided on the web site of the given tool. Absolute must is to record user scenarios and play them with significant amount of users. Try to make it as realistic as possible. Even if this evaluation cost more time, just spend it, it will save a lot of time and money in the long run. This evaluation will give you confidence that tool can do the job and can be used by QAs responsible for the performance testing project.

Implement the scenarios

Some of the work should have already been done during the evaluation demo. Scenarios now must be polished to make them match real user experience as much as possible. It is good idea to be able to implement a mechanism for changing of scenarios just by a configuration.

Essence of performance testing

In terms of Web or API (REST, SOAP) performance testing every tool, no matter how fancy it is, in the end does one and the same, sends HTTP requests to the server, collects and measures the response. This is it, not a rocket science.

Include static resources or not?

This is important question in case of Web performance testing. There is no fixed recipe though. Successful web applications use content delivery network (CDN) to server static content such as images, CSS, JavaScripts, media. If CDN is third party and they provide some service level agreements (SLAs) for response time then static data should be skipped in performance test. If it is our CDN then it may be good idea to make separate performance testing project just for CDN itself. This could double the effort, but will make each projects focused and coherent. If static data is hosted on the same server as dynamic content then it may be good idea to include images also. It very much depends on the situation. Browsers do have cache but it is controlled by correct HTTP response header values. In case of incorrect such or too dynamic static content this can put significant load on the server.

Virtual users vs. requests/second

Tools for performance testing use virtual user as main metric. This is a representation of a real life user. With sleep times between requests they mimic real user behaviour on the application and this gives very close to reality simulation. The metric though is more business orientated. The more technical metric is requests per second. This is what most traffic monitoring tools report. But converting between those is a tricky task. It really depends how application is performing. Will try to illustrate it with some examples. Lets consider 100 users with sleep time of 1 second between requests. This theoretically should give 100 request per second load. But if application is responding more slowly than 1 second then it will produce less req/s as each user has to wait for the response and then sent next request. Lest consider 10 users with no sleep time. If application responds for 100 ms then each user will make 10 req/s this sums to total of 100 req/s. If application responds with 1 second then load will drop to 10 req/s. If application responds with 2 second then load will drop to 5 req/s. In reality it takes several attempts to match users count with expected request per second and all those depend on the application’s response time.

Environments

With the start of the project tests can be run on test servers or local QA/Dev machines. Sometimes problems are caught even at this level. Especially when performance testing is a big event in the company I recommend first do it locally, this could save some embarrassment. Also this helps polish even better the scenarios.Ones everything is working perfect locally then we can start with actual performance testing. Environments to be used for performance testing should be production like. The closer they are, the better. Once everything is good at production-like server the cherry on top will be if tests can be run on production in times of no usage. Beware when running the tests and you try to see at what amount of users system will fail, as your test/production machine could be VM and this may affect other important VMs.

Measure

Each performance testing tool gives some reporting about response times, total number of requests, request per second, responses with errors. This is good, but do not trust this reports. Performance testing tools like any software has bugs. You should definitely have some server monitoring software or application performance measurement tool installed on machine under test. Those tools will give you most adequate information as long as memory usage statistics and even hints where problems may occurred.

Conclusion

Performance testing is important part of an application life-cycle. It should be done correctly to get good results.

Read more...

What about code coverage

Last Updated on by

Post summary: Code coverage is measurement of what percentage of program source code is being executed by your tests. Code coverage is a nice to have, but in no case make code coverage ultimate goal!

Code coverage is useful metric to check what part of the code your tests are exercising. Is really depends on the tools to be used for gathering code coverage metrics but in general they work in similar fashion.

How it works

One approach is to instrument application under test. Instrumentation is to modify original executables by adding meta data so code coverage tool is able to understand which line of code is being executed. Other option is to run the application through code coverage tool. In both ways once application is running tests are being executed.

What tests to run

Tests that can be run to measure code coverage can be unit tests, functional automation tests or even manual tests. It doesn’t matter the important part is to see how our tests are impacting application under test.

Results

Once tests are finished code coverage metrics are obtained from code coverage tool. To have detailed information most of the tools take original source code and generate visual report with colour information which line is executed and which not. There are different levels of coverage, method, line, code block, etc. I personally prefer lines and when speaking further I’ll mean lines of code executed.

Benefits

Code coverage information is equally useful for QA and developers. QA analyse code that has not being executed during tests to identify what tests conditions they are missing and improve their tests. Developers analyse the results to identify and remove dead or unused code.

When to do it

Code coverage is a nice to have activity. We can live with or without it. It is useful for big matured products where there is automation test suites. You can also do them against your tests code in order to optimise it. Removing dead code optimises the product and makes its maintenance easier. I would say doing it too often should be avoided. Everything depends on context but for me best is once or twice a year.

What does code coverage percentage means

In one word – nothing. You may have 30% of code coverage but to cover most important user functionality and bug rate to be low and you may have 90% with dummy tests made especially to exercise some code without the idea of actually testing it. I was lucky to work on a project where developers keep the code tidy and clean and my tests easily accomplished 81% just by verifying all user requirements. I may say 80-85% is the maximum you may get.

Pitfalls

Do not ever put code coverage as important measurement or key performance indicator (KPI) in your testing strategy. Doing so and making people try to increase the code coverage will in most cases result in dummy tests made especially this percentage to go up. Code coverage is in most cases insignificant aspect of your testing strategy.

How to do it

Tutorial how to do code coverage for Java with JaCoCo can be found in Code coverage of manual or automated tests with JaCoCo post. Tutorial how to do code coverage for Java with OpenCover can be found in Code coverage of manual or automated tests with OpenCover for .NET applications post.

Conclusion

Code coverage is interesting aspect of testing. It might enhance your tests if done wisely or it can ruin them. Remember tests scenarios should be extracted from user requirements and features. Code coverage data should be used to see if you have some blind spots reading the requirements. It can help developers remove dead or unused code.

Read more...