Unit Testing Activity

Similar documents
Unit Tes2ng Ac2vity. SWEN-261 Introduc2on to So3ware Engineering. Department of So3ware Engineering Rochester Ins2tute of Technology

Unit Testing. SWEN-610 Foundations of Software Engineering. Department of Software Engineering Rochester Institute of Technology

Unit Testing. SWEN-261 Introduction to Software Engineering. Department of Software Engineering Rochester Institute of Technology

Web Architecture and Development

Web Architecture and Development

Checking Current Code Coverage

Topics covered. Introduction to JUnit JUnit: Hands-on session Introduction to Mockito Mockito: Hands-on session. JUnit & Mockito 2

Introduction to Software Engineering: Tools and Environments. Session 5. Oded Lachish

CS159. Nathan Sprague. September 30, 2015

Domain-Driven Design Activity

Classes, interfaces, & documentation. Review of basic building blocks

Object-Oriented Design I - SOLID

Test Isolation and Mocking

Mock Objects and the Mockito Testing Framework Carl Veazey CSCI Friday, March 23, 12

Accessibility. Adding features to support users with impaired vision, mobility, or hearing

mvn package -Dmaven.test.skip=false //builds DSpace and runs tests

Testing on Android. Mobile Application Development. Jakob Mass MTAT Fall MTAT

Testing. Topics. Types of Testing. Types of Testing

Tools for Unit Test JUnit

Tools for Unit Test - JUnit

Advanced Object Oriented Programming EECS2030E

CS 170 Java Programming 1. Week 13: Classes, Testing, Debugging

Software Development Tools. COMP220/COMP285 Sebastian Coope Eclipse and JUnit: Creating and running a JUnit test case

Programmieren II. Unit Testing & Test-Driven Development. Alexander Fraser.

Chapter 11 Paper Practice

Announcements. Lab tomorrow. Quiz Thursday P3 due Friday. Exceptions and unit testing

Tutorial 3: Unit tests and JUnit

Unit testing. JUnit. JUnit and Eclipse. A JUnit test class 3/6/17. A method is flagged as a JUnit test case.

Test-Driven Development (a.k.a. Design to Test) CSE260, Computer Science B: Honors Stony Brook University

CS410J: Advanced Java Programming

Junit Overview. By Ana I. Duncan

After completing Matchers, you will be able to: Describe the advantages of encapsulating verification logic in

COE318 Lecture Notes Week 10 (Nov 7, 2011)

Step 2. Creating and running a project(core)

Motivating Example: Two Types of Errors (2) Test-Driven Development (TDD) with JUnit. Motivating Example: Two Types of Errors (1)

public static boolean isoutside(int min, int max, int value)

Test-Driven Development (TDD) with JUnit

Unit testing. unit testing: Looking for errors in a subsystem in isolation. The basic idea: JUnit provides "assert" commands to help us write tests.

Software Engineering I (02161)

Testing with Soap UI. Tomaš Maconko

CS 215 Software Design Homework 3 Due: February 28, 11:30 PM

Comp215: Enums / Testing

CS11 Advanced Java. Winter Lecture 2

Advanced Object Oriented Programming EECS2030Z

Thinking Functionally

White-box testing. Software Reliability and Testing - Barbara Russo SERG - Laboratory of Empirical Software Engineering.

Jtest Tutorial. Tutorial

JUnit tes)ng. Elisa Turrini

Software Construction

Software Engineering I (02161)

A Guided Tour of Test Automation

Example cdi-produces-field can be browsed at

CS 251 Intermediate Programming Methods and Classes

CS 251 Intermediate Programming Methods and More

Pieter van den Hombergh Stefan Sobek. April 18, 2018

Chair of Software Engineering. Java and C# in depth. Carlo A. Furia, Marco Piccioni, Bertrand Meyer. Java: reflection


JUNIT 5 EXTENSIONS 1. 1

Programming Project: Game of Life

Unit Testing : Software Testing

Javadoc. Computer Science and Engineering College of Engineering The Ohio State University. Lecture 7

print statements, debugger expressions, test scripts. Writing expressions in a debugger only that t a program works now. An application typically

ASSERTIONS AND LOGGING

Functional Testing (Testování funkčnosti)

Principles of Software Construction: Testing: One, Two, Three

IntelliJ IDEA Static Code Analysis Hamlet D'Arcy

CS 3 Introduction to Software Engineering. 3: Exceptions

P2: Exercise 2 Discussion. Pooja Rani

Defensive Coding Techniques. Independent Consultant Developer Mentor

Pages and 68 in [JN] conventions for using exceptions in Java. Chapter 8 in [EJ] guidelines for more effective use of exceptions.

JAVA. 1. Introduction to JAVA

JUnit Testing Patterns: Mocking and Doubles

CSE 331 Midterm Exam Sample Solution 2/18/15

Pro ASP.NET MVC 2 Framework

CSE331 Winter 2014, Midterm Examination February 12, 2014

CSE 331 Final Exam 3/16/15 Sample Solution

JUNIT 5 & TESTCONTAINERS. Testing with Java and Docker

JUnit Testing Framework Architecture

Maven Plugin Guide OpenL Tablets BRMS Release 5.16

Junit. Presentation & Tools (Eclipse, Maven, Mockito, Spring)

Object-oriented Programming Project

public static void negate2(list<integer> t)

CS 170 Java Programming 1. Week 12: Creating Your Own Types

11 Using JUnit with jgrasp

CSE 331 Final Exam 6/5/17 Sample Solution

Testing. Technion Institute of Technology Author: Assaf Israel. Author: Assaf Israel - Technion

Beyond JUnit: Introducing TestNG The Next Generation in Testing

Basic Keywords Practice Session

Software LEIC/LETI. Lecture 5

Design for Testability. Dave Liddament (Director and developer at Lamp Bristol Limited)

The most frequently asked questions about JUnit are answered here (especially sections 4, 5 and 7):

Object-Oriented Design II - GRASP

Exceptions and Libraries

Reflection (in fact, Java introspection)

Advanced Java Testing. What s next?

JVA-117A. Spring-MVC Web Applications

Training topic: OCPJP (Oracle certified professional Java programmer) or SCJP (Sun certified Java programmer) Content and Objectives

Software-Architecture Unit Testing (JUnit)

EECS 4313 Software Engineering Testing

Exception Handling. Sometimes when the computer tries to execute a statement something goes wrong:

Transcription:

Unit Testing Activity SWEN-261 Introduction to Software Engineering Department of Software Engineering Rochester Institute of Technology

Your activity for the Unit Testing lesson is to build tests for existing Project components. These slides direct you through the process of creating unit tests for your project. Activity actions are highlighted in green with a checkmark. But first, these slides provide technical details on: 1. How to organize test classes using Maven 2. How to run tests using Maven 3. How to structure a typical test class 4. How to use JUnit assertion functions 5. How to use package-private constants in test code 6. How to use Mockito mock objects using Dependency Injection 2

Maven provides a convenient structure for organizing unit test code. Put your test classes in a separate source path. The goal is to keep the test source code separate from the production source code. Using Maven that is usually src/test/java. Create this directory if it doesn't already exist. (Optional) Link your IDE to this source path. Most IDEs provide wizards for creating unit tests. Make sure the IDE stores the test classes in the proper source path. The unit test code examples in these slides are from the Guessing Game. See the Unit Testing topic page for a link to the ZIP file. 3

Maven will run tests during builds and there is also the test target. 4 [~/workspace/guessing-game] mvn clean test [INFO] Scanning for projects... // SKIPPING SOME Maven OUTPUT ------------------------------------------------------- T E S T S ------------------------------------------------------- Running com.example.model.guessgametest Tests run: 11, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 4.578 sec Running com.example.ui.postguessroutetest Tests run: 5, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.955 sec Running com.example.ui.gameviewtest Tests run: 3, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 1.182 sec Running com.example.ui.gethomeroutetest Tests run: 2, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.122 sec Running com.example.ui.homeviewtest Tests run: 3, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.056 sec Running com.example.ui.getgameroutetest Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0 sec Running com.example.appl.playerservicestest Tests run: 9, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.001 sec Running com.example.appl.gamecentertest Tests run: 4, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.001 sec Results : Tests run: 38, Failures: 0, Errors: 0, Skipped: 0 [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------

The structure of a unit test class. Name the test class after the component under test (CuT) in the same package. So if CuT is com.example.model.myentity Then test class is: com.example.model.myentitytest Doing so gives the test code package-private access to CuT class. Annotate each test method with. Use an @Before annotated method for setup common to all test scenarios Use an @After annotated method to clean up. 5

Recall the checklist of types of unit tests. Business logic Tests for each path through a method Happy path as well as failure paths Constructors and accessors Defensive programming checks Validation of method arguments NullPointerException IllegalArgumentException Validation of component state IllegalStateException The equals and hashcode methods, as needed Exception handling 6

Here's an example unit test suite for the GuessGame class. 7 package com.example.model; import static org.junit.assert.*; import org.junit.before; import org.junit.test; public class GuessGameTest { @Before public void testsetup() {... public void ctor_noarg() {... public void ctor_witharg() {... (expected = IllegalArgumentException.class) public void ctor_toobig() {... (expected = IllegalArgumentException.class) public void ctor_toosmall() {... (expected = IllegalArgumentException.class) public void make_an_invalid_guess() {... (expected = IllegalArgumentException.class) public void make_an_invalid_guess_too_big() {... public void isvalidguess() {... public void testgameplay_win_first_try() {... public void testgameplay_win_second_try() {... public void testgameplay_win_last_try() {... public void testgameplay_loose() {... Import JUnit assertion functions. Setup for the tests. Test constructors. Test defensive programming checks. Test business logic.

Here's an example test method for the GuessGame class. import static org.junit.assert.*; import org.junit.test; public class GuessGameTest { public void testgameplay_win_first_try() { // Arrange the test scenario & invoke test (on ctor) final GuessGame CuT = new GuessGame(NUMBER,gameCenter); // Analyze results: game start asserttrue(cut.isgamebeginning()); asserttrue(cut.hasmoreguesses()); assertequals(3, CuT.guessesLeft()); // Invoke test: first guess, correct asserttrue(cut.makeguess(number)); 8 // Analyze results assertfalse(cut.isgamebeginning()); asserttrue(cut.hasmoreguesses()); assertequals(2, CuT.guessesLeft()); verify(gamecenter).gamefinished();

Here's an example of how to test an expected exception. Use the annotation expected attribute: 9 public class GuessGameTest { private static final int TOO_BIG = 10; (expected = IllegalArgumentException.class) public void ctor_toobig() { new GuessGame(TOO_BIG); Roughly the same as: public class GuessGameTest { private static final int TOO_BIG = 10; public void ctor_toobig() { try { new GuessGame(TOO_BIG); fail("ctor should fail."); catch (IllegalArgumentException e) { // success, do nothing

JUnit has many built-in assertions you can use. 10 Test truth-hood asserttrue([message,] condition) assertfalse([message,] condition) Test values or objects for equality assertequals([message,] expected, actual) assertnotequals([message,] expected, actual) Test objects for identity (obj1 == obj2) assertsame([message,] expected, actual) assertnotsame([message,] expected, actual) Test null-hood assertnull([message,] object) assertnotnull([message,] object) Automatic failure: fail(message)

Recall the coding tip recommended. Idioms for testable code: Make message strings (and other values) constants Make these members package-private (or public) Example: public class GameCenter { public final static String NO_GAMES_MESSAGE = "No games have been played so far."; public final static String ONE_GAME_MESSAGE = "One game has been played so far."; public final static String GAMES_PLAYED_FORMAT = "There have been %d games played."; public synchronized String getgamestatsmessage() { if (totalgames > 1) { return String.format(GAMES_PLAYED_FORMAT, totalgames); else if (totalgames == 1) { return ONE_GAME_MESSAGE; else { return NO_GAMES_MESSAGE; 11

Here's how the test code would use these members to test multiple games being played. public void game_statistics_message_0() { // Setup the test scenario: no games play yet final GameCenter CuT = new GameCenter(); // Analyze the results assertequals(gamecenter.no_games_message, CuT.getGameStatsMessage()); public void game_statistics_message_1() { final GameCenter CuT = new GameCenter(); // Simulate a single game ending CuT.gameFinished(); // * Analyze the results assertequals(gamecenter.one_game_message, CuT.getGameStatsMessage()); public void game_statistics_message_2() { final GameCenter CuT = new GameCenter(); // Simulate two games ending CuT.gameFinished(); CuT.gameFinished(); // * Analyze the results assertequals(string.format(gamecenter.games_played_format, 2), CuT.getGameStatsMessage()); 12,

When components have dependencies you have to consider how to isolate the dependencies. Dependencies are isolated along the testing seam for a component. There are three elements to consider Component under Test (CuT) Friendly dependencies that can be trusted to work Other dependencies that must have mocks because they are not trusted or we need special control during the test Friendly Mocks 13

The UI routes are an interesting case because there are two components to test. The route itself creates the view map that the template engine uses The template engine receives the view map and uses the view template to generate the view HTML Each of those is a component to test. For example, for making guesses in the Guessing Game PostGuess Route View map Template Engine and Game View Rendered HTML 14

These are the two testing configurations for making a guess. TEST SEAM PostGuessRoute Test PostGuess Route Friendly Game Center Guess Game Request GameView Test Template Engine and Game View Mocks Session Player Services Template Engine and Game View Simulate the guess Because the PostGuess route does not expose the view map, get access to it through Answer object. Generate view map Check the HTML 15

First, a quick review of dependency injection which is a key design technique to make classes testable. public class PostGuessRoute implements Route { private final GameCenter gamecenter; private final TemplateEngine templateengine; /** * The constructor for the {@code POST /guess route handler. * * @param gamecenter * The {@link GameCenter for the application. * * @param templateengine * template engine to use for rendering HTML page * * @throws NullPointerException * when the {@code gamecenter parameter is null */ This class is instantiated by the WebServer component, which configures Spark. This JDK method performs a null check and throws an NPE if violated. PostGuessRoute(GameCenter gamecenter, TemplateEngine templateengine { // validation Objects.requireNonNull(gameCenter, "gamecenter must not be null"); Objects.requireNonNull(templateEngine, "templateengine must not be null"); this.gamecenter = gamecenter; this.templateengine = templateengine; The WebServer component injects these two dependencies into this route. 16

Some classes are thoroughly tested and can be considered friendly; others we must mock. import static org.junit.assert.*; import static org.mockito.mockito.*; Import Mockito functions public class PostGuessRouteTest { private static final int NUMBER = 7; private static final int WRONG_GUESS = 3; private static final String WRONG_GUESS_STR = Integer.toString(WRONG_GUESS); private static final String NOT_A_NUMBER = "asdf"; private static final int INVALID_GUESS = 47; private static final String INVALID_GUESS_STR = Integer.toString(INVALID_GUESS); /** * The component-under-test (CuT). */ private PostGuessRoute CuT; // friendly objects private GameCenter gamecenter; private GuessGame game; // attributes holding mock objects private Request request; private Session session; private TemplateEngine engine; private PlayerServices playersvc; GameCenter and Game are tested so we consider them friendly. These we need to mock to isolate the unit under test. 17

We have to setup the mocks before each test. @Before public void setup() { Use the Mockito mock function to request = mock(request.class); create a mock object session = mock(session.class); when(request.session()).thenreturn(session); Use the Mockito when and engine = mock(templateengine.class); thenreturn APIs to simulate a method call on a mock object. // build the Service and Model objects // the GameCenter and GuessingGame are friendly gamecenter = new GameCenter(); game = new GuessGame(NUMBER, gamecenter); // but mock up the PlayerService playersvc = mock(playerservices.class); when(playersvc.currentgame()).thenreturn(game); // store in the Session when(session.attribute(gethomeroute.playerservices_key)).thenreturn(playersvc); // create a unique CuT for each test CuT = new PostGuessRoute(gameCenter, engine); Inject the setup mocks into the CuT. 18

We set up to test the PostGuessRoute including access to data on the Route-TemplateEngine seam. Mockito's Answer mechanism allows us to save, and later analyze intermediate data crossing the seam. public void bad_guess_1() { For this specific test case, we also need to specify the Request 'guess' query parameter. // Arrange the test scenario: The user's guess is not valid number. when(request.queryparams(eq(postguessroute.guess_param))).thenreturn(not_a_number); // To analyze what the Route created in the View-Model map you need // to be able to extract the argument to the TemplateEngine.render method. // Mock up the 'render' method by supplying a Mockito 'Answer' object // that captures the ModelAndView data passed to the template engine final MyModelAndView mymodelview = new MyModelAndView(); when(engine.render(any(modelandview.class))).thenanswer(mymodelandview.makeanswer(mymodelview )); Copy the MyModelAndView class file to your ui test directory to use in unit tests of your project's routes. 19

With the mocks setup, now direct the scenario of the test. public void bad_guess_1() {... // Invoke the test CuT.handle(request, response); // Analyze the results: // * model is a non-null Map final Object model = mymodelview.model; assertnotnull(model); asserttrue(model instanceof Map); // * model contains all necessary View-Model data @SuppressWarnings("unchecked") final Map<String, Object> vm = (Map<String, Object>) model; assertequals(getgameroute.title, vm.get(gethomeroute.title_attr)); assertequals(boolean.false, vm.get(gethomeroute.new_player_attr)); assertequals(postguessroute.error_type, vm.get(postguessroute.message_type_attr)); assertequals(postguessroute.makebadargmessage(not_a_number), vm.get(postguessroute.message_attr)); // * test view name assertequals(getgameroute.view_name, mymodelview.viewname); For this test of the route itself, we do not care about the HTML generated by the call to handle(). 20

There will also be a suite of unit tests to check if the view generates the correct HTML. public class GameViewTest { This is what we expect in the generated HTML. private static final String TITLE = "MyTitle"; private static final String TITLE_HEAD_TAG = "<title>" + TITLE + "</title>"; private static final String TITLE_H1_TAG = "<h1>" + TITLE + "</h1>"; private static final String GAME_HEADING_1ST_TAG = "<h4>make a Guess</h4>"; private static final String GAME_HEADING_TAG = "<h4>make Another Guess</h4>"; private static final String BAD_GUESS_MSG = "Bad guess."; /** * Make the HTML text for a div element that holds a user message. */ private static String makemessagetag(final String text, final String type) { return String.format("<div class=\"message %s\">%s</div>", type, text); Some helper methods to create other expected HTML strings. /** * Make the message text for how many guesses are left. */ private static String makeguessesleftmsg(final int guessesleft) { if (guessesleft > 1) { return String.format("You have %d guesses left.", guessesleft); else { return "You have 1 guess left."; private final TemplateEngine engine = new FreeMarkerEngine(); 21 The component under test.

The test will check the rendered HTML for one of the view scenarios. public class GameViewTest {... /** * Test that the Game view displays when the guess was bad. */ public void bad_data_message() { // Arrange test final Map<String, Object> vm = new HashMap<>(); final ModelAndView modelandview = new ModelAndView(vm, GetGameRoute.VIEW_NAME); // setup View-Model for a new player vm.put(gethomeroute.title_attr, TITLE); vm.put(getgameroute.game_begins_attr, false); vm.put(postguessroute.message_attr, BAD_GUESS_MSG); vm.put(postguessroute.message_type_attr, PostGuessRoute.ERROR_TYPE); vm.put(getgameroute.guesses_left_attr, 2); Create the view map for this test scenario. 22 // Invoke test final String viewhtml = engine.render(modelandview); // Analyze results // * look for Title elements asserttrue("title head tag exists.", viewhtml.contains(title_head_tag)); asserttrue("title heading tag exists.", viewhtml.contains(title_h1_tag)); // * look for the Game heading asserttrue("the Game heading tag exists.", viewhtml.contains(game_heading_tag)); // * look for the error message asserttrue("error message tag exists.", viewhtml.contains(makemessagetag(bad_guess_msg, PostGuessRoute.ERROR_TYPE))); // * look for the 'Guesses left' message asserttrue("guesses left message exists.", viewhtml.contains(makeguessesleftmsg(2))); Verify that the HTML has Generate the view HTML. the strings that we expect.

Mockito has a rich API for setting scenarios and for inspecting test activity. 23 Arranging scenarios: when(mock.method(args)).thenreturn(value) when(mock.method(args)).thenthrow(new XyzExc()) when(mock.method(args)).thenanswer(lambda) Inspecting activity within the CuT method: verify(mock).method(args) verify(mock, times(1)).method(args) Other verification modes: times(n), atleast(n), atmost(n) & never() Specifying arguments: An actual value or object: eq(value) or eq(object) Any value (anyint(), etc); any() for any Object Many more types of Matchers

Your exercise is to build unit tests for two classes in your Project. Each team member picks two classes in your project and builds unit tests for them. Each team member will pick different classes to test. If you need to refactor the code to make the component more testable then do so. Create the test class in the appropriate package in the test source path. Create a reasonable set of test cases. At least three test cases for each CuT. Focus on the business logic methods (eg, the handle method for UI Controllers). 24

Your exercise is to build unit tests for two classes in your Project. Upload the two unit test source files to the Unit testing - individual Dropbox in MyCourses. You will now complete the Definition of Done unit testing checklist items to consider the story done. 25