Technion – Institute of Technology Author: Gal Lalouche ©

Slides:



Advertisements
Similar presentations
Exceptions CSE301 University of Sunderland Harry Erwin, PhD.
Advertisements

Unit Testing Australian Development Centre Brisbane, Australia.
11-Jun-14 The assert statement. 2 About the assert statement The purpose of the assert statement is to give you a way to catch program errors early The.
MAHDI OMAR JUNIT TUTORIAL. CONTENTS Installation of Junit Eclipse support for Junit Using Junit exercise JUnit options Questions Links and Literature.
Unit and Functional Testing with JUnit and Related Tools Greg Barnes University of Washington
Objectives: Test Options JUnit Testing Framework TestRunners Test Cases and Test Suites Test Fixtures JUnit.
Approach of Unit testing with the help of JUnit Satish Mishra
API Design CPSC 315 – Programming Studio Fall 2008 Follows Kernighan and Pike, The Practice of Programming and Joshua Bloch’s Library-Centric Software.
JUnit. What is unit testing? A unit is the smallest testable part of an application. A unit test automatically verifies the correctness of the unit. There.
JUnit, Revisited 17-Apr-17.
JUnit. Why is testing good? Due to psychological factors, programmers are bad testers. A computer can test much faster than a human Philosophy: “If it.
OOP #10: Correctness Fritz Henglein. Wrap-up: Types A type is a collection of objects with common behavior (operations and properties). (Abstract) types.
TDD Test-Driven Development. JUnit 4.0 To use annotations need to import org.junit.Test To use assertion need to import org.junit.Assert.* No need to.
Software Testing. “Software and Cathedrals are much the same: First we build them, then we pray!!!” -Sam Redwine, Jr.
Presentation Outline What is JUnit? Why Use JUnit? JUnit Features Design of JUnit Downloading JUnit Writing Tests – TestCase – TestSuite Organizing The.
14-Jul-15 JUnit 4. Comparing JUnit 3 to JUnit 4 All the old assertXXX methods are the same Most things are about equally easy JUnit 4 makes it easier.
Unit Testing & Defensive Programming. F-22 Raptor Fighter.
1 Some Patterns of Novice Programs Author : Eugene Wallingford ; Dan Steinberg ; Robert Duvall ; Ralph Johnson Source : PLoP 2004 Advisor : Ku-Yaw Chang.
© Dr. A. Williams, Fall Present Software Quality Assurance – JUnit Lab 1 JUnit A unit test framework for Java –Authors: Erich Gamma, Kent Beck Objective:
JUnit The framework. Goal of the presentation showing the design and construction of JUnit, a piece of software with proven value.
Testing. What is Testing? Definition: exercising a program under controlled conditions and verifying the results Purpose is to detect program defects.
1 Debugging and Testing Overview Defensive Programming The goal is to prevent failures Debugging The goal is to find cause of failures and fix it Testing.
CSE 219 Computer Science III Testing. Testing vs. Debugging Testing: Create and use scenarios which reveal incorrect behaviors –Design of test cases:
Unit testing Unit testing TDD with JUnit. Unit Testing Unit testing with JUnit 2 Testing concepts Unit testing Testing tools JUnit Practical use of tools.
Test Isolation and Mocking Technion – Institute of Technology Author: Gal Lalouche © 1 Author: Gal Lalouche - Technion 2015 ©
Introduction CS 3358 Data Structures. What is Computer Science? Computer Science is the study of algorithms, including their  Formal and mathematical.
Dependency Injection Technion – Institute of Technology Author: Gal Lalouche - Technion 2015 ©
Best Practices. Contents Bad Practices Good Practices.
Testing and Debugging Session 9 LBSC 790 / INFM 718B Building the Human-Computer Interface.
Introduction to JUnit 3.8 SEG 3203 Winter ‘07 Prepared By Samia Niamatullah.
Unit Testing with JUnit and Clover Based on material from: Daniel Amyot JUnit Web site.
Refactoring & Testability. Testing in OOP programming No life in flexible methodologies and for refactoring- infected developers without SOME kind of.
What is Testing? Testing is the process of finding errors in the system implementation. –The intent of testing is to find problems with the system.
JUnit Don Braffitt Updated: 10-Jun-2011.
JUnit A framework which provides hooks for easy testing of your Java code, as it's built Note: The examples from these slides can be found in ~kschmidt/public_html/CS265/Labs/Java/Junit.
JUnit. Introduction JUnit is an open source Java testing framework used to write and run repeatable tests JUnit is integrated with several IDEs, including.
David Streader Computer Science Victoria University of Wellington Copyright: David Streader, Victoria University of Wellington Debugging COMP T1.
Copyright 2007 SpringSource. Copying, publishing or distributing without express written permission is prohibited. Testing Spring Applications Unit Testing.
S Ramakrishnan1 Systems V & V, Quality and Standards Dr Sita Ramakrishnan School CSSE Monash University.
1 Unit Testing with JUnit CS 3331 JUnit website at Kent Beck and Eric Gamma. Test Infected: Programmers Love Writing Tests, Java Report,
ICS3U_FileIO.ppt File Input/Output (I/O)‏ ICS3U_FileIO.ppt File I/O Declare a file object File myFile = new File("billy.txt"); a file object whose name.
PROGRAMMING TESTING B MODULE 2: SOFTWARE SYSTEMS 22 NOVEMBER 2013.
Programming & Debugging. Key Programming Issues Modularity Modifiability Ease of Use Fail-safe programming Style Debugging.
Unit Testing. F-22 Raptor Fighter Manufactured by Lockheed Martin & Boeing How many parts does the F-22 have?
Unit Testing with FlexUnit
Justin Bare and Deric Pang with material from Erin Peach, Nick Carney, Vinod Rathnam, Alex Mariakakis, Krysta Yousoufian, Mike Ernst, Kellen Donohue Section.
Reasoning and Design (and Assertions). How to Design Your Code The hard way: Just start coding. When something doesn’t work, code some more! The easier.
Today protected access modifier Using the debugger in Eclipse JUnit testing TDD Winter 2016CMPE212 - Prof. McLeod1.
Winter 2006CISC121 - Prof. McLeod1 Last Time Reviewed class structure: –attributes –methods –(inner classes) Looked at the effects of the modifiers: –public.
Test Isolation and Mocking Technion – Institute of Technology Author: Gal Lalouche © 1 Author: Gal Lalouche - Technion 2016 ©
Testing Technion – Institute of Technology Author: Gal Lalouche © 1 Author: Gal Lalouche - Technion 2016 ©
OOP Tirgul 7. What We’ll Be Seeing Today  Packages  Exceptions  Ex4 2.
CSE 143 Lecture 14: testing.
SWE 434 SOFTWARE TESTING AND VALIDATION LAB2 – INTRODUCTION TO JUNIT 1 SWE 434 Lab.
Technion – Institute of Technology Author: Gal Lalouche ©
Unit Testing.
Software Construction Lab 10 Unit Testing with JUnit
Test Isolation and Mocking
CMPE212 – Stuff… Assn 2 due this Friday. Winter 2018
Test-driven development (TDD)
Introduction to JUnit CS 4501 / 6501 Software Testing
Introduction to JUnit IT323 – Software Engineering II
Test Driven Development
CS 240 – Advanced Programming Concepts
Section 4: Graphs and Testing
Test Driven Development
CSE 143 Lecture 5 More ArrayIntList:
Assertions References: internet notes; Bertrand Meyer, Object-Oriented Software Construction; 4/25/2019.
Computer Science 340 Software Design & Testing
JUnit Dwight Deugo Nesa Matic Portions of the notes for this lecture include excerpts from the Eclipse 3.0 and.
Presentation transcript:

Technion – Institute of Technology 236700 Author: Gal Lalouche © Testing Author: Gal Lalouche - Technion 2015 © Technion – Institute of Technology 236700 Author: Gal Lalouche ©

Why (unit) test? Programming is incremental by nature We want to verify we haven’t broken anything Tests not only examine the code’s functionality but also its Ease of use API Boilerplate & setup Error path behavior Coherency and Coupling issues Tests are the usage example of our code and are an excellent source for documentation Author: Gal Lalouche - Technion 2015 ©

Testable Code → Good Code Tests are usually the first time outside code will use your production code Is the production code hard to use? Is object creation long and complex? Are methods cryptic with lots of parameters? How does your production code handle usage errors? Have you been surprised by a method’s behavior? Is the production code hard to test? Do you write 10-15 LOC before you reach the assert line? Is it difficult to assert the desired behavior? Do you find it hard isolating the tested feature? Are you not even sure what you should be asserting? Author: Gal Lalouche - Technion 2015 © The most important reason to write tests is the improvement in the tested code design

Test types Unit Tests – Test a single element of the system Our focus today Unit Tests – Test a single element of the system Integration Tests – Verify that a few units can work together and are wired up correctly End-to-End Tests – Test the complete flow of interactions throughout the system No “mocks”/”stubs”/”fakes” Acceptance / Business logic Tests – Answers the question: “Did we build what we wanted?” Usually centered around a user story Author: Gal Lalouche - Technion 2015 © Single elements does not imply a single class In the next tutorial we will discuss how to avoid writing integration tests when testing elements that are dependent on other elements

Test types Author: Gal Lalouche - Technion 2015 © http://blog.jonasbandi.net/2010/09/acceptance-vs-integration-tests.html

Testing Framework – Wish list Better Asserts: Validating results Vs. expectations assert(sqrt(4) == 2) Vs. assertEqual(2,sqrt(4)) assert(x != null) Vs. assertNotNull(x) Clear indication of Success / Failure Meaningful message upon failure Ease of use – Should be easy to add new Tests Aggregate tests together into Test Cases / Tests Suites Continue with other tests even if a test fails / throws an exception No duplication of initialization code of tested objects Side effects should not influence other tests Author: Gal Lalouche - Technion 2015 ©

JUnit A unit testing framework for Java A Test is a Method http://www.junit.org A Test is a Method A Test Case is a class which includes tests methods Aggregates tests for a single tested unit A Test Suite is a collection of Test Cases / Test Suites (or both) Used to create a hierarchy of tests Author: Gal Lalouche - Technion 2015 ©

JUnit 4.0 A step up from JUnit 3.0 New Assertions methods in org.junit.Assert.* No need to extend from junit.framework.TestCase No need to prefix test methods with ‘test’ Test methods are annotated with @Test @BeforeClass – runs once before first test Setting up the stubs objects / DB Connections @AfterClass – runs once after the last test Closing DB connections @Before method – runs before every test Preparing data Could be used for advanced construction @After method – runs after every test Resetting stubs / cleaning data Author: Gal Lalouche - Technion 2015 ©

JUnit test case life-cycle @A* - Running all methods annotated with A Test Case Class load Static C’tor @BeforeClass* C’tor @Before* @Test @After* C’tor @Before* @Test @After* C’tor @Before* @Test @After* C’tor @Before* @Test @After* Author: Gal Lalouche - Technion 2015 © Note that the constructor is called before every test; use before for more complicated initializations Avoid using multiple methods with the same lifecycle annotation (before, after, etc.) @AfterClass*

JUnit life-cycle - Example Local resources should be initialized and cleaned before/after every test Author: Gal Lalouche - Technion 2015 © @BeforeClass and @AfterClass must be static

JUnit life-cycle - Example Expensive and global resources can be initialized and destroyed before/after all tests Author: Gal Lalouche - Technion 2015 ©

Name is testing scenario JUnit 4.0 - Example Assuming we want to test a new Stack interface implementation Smart Asserts: assertNotEqual, assertTrue, assertSame, assertNotNull, assertArrayEqual, etc. Name is testing scenario Initialization Author: Gal Lalouche - Technion 2015 © Naming is important! Don’t just name it testPeek Expectation Result org.junit.ComparisonFailure: expected:<[LAST]-ITEM> but was:<[FIRST]-ITEM>

Ideal Test A recipe for a good test: If (1) and (2) are needed at all (e.g., initialization in constructor/@Before), it will be as short as possible (ideally just calls to new) (3) will be a single method invocation (4) will be a single assert Of course this ideal cannot always be achieved But if you can’t, you should always ask yourselves why? @Test public void testShouldNameExplicitlyStatesExpectation() { (1) – Initialize collaborators (optional) (2) – Initialize object under test (optional) (3) – Exercise behavior (4) – Assert outputs } Author: Gal Lalouche - Technion 2015 © Keeping this test structure guarantees: The test examines a single behavior When the test fails It will be easy pinpointing the root cause Good production code characteristics (mainly coherence)

Specifies the name of the invoked method but not the desired behavior Test names – bad It should be easy pin-pointing the problem when a test fails without looking at its code Consider the following test: How about addItemWithOutOfStockProduct? Describes the method and the parameter Still not a good name – does not describes the desired behavior Bad name. Specifies the name of the invoked method but not the desired behavior @Test public void addItemTest() {   Product p = new Product();   p.setAvailable(false);   ShoppingCart cart = new ShoppingCart();   cart.addItem(p);   assertEquals(0, p.numItems()); } Author: Gal Lalouche - Technion 2015 ©

Test names – good It should be trivial understanding what is the expected behavior from the name alone We do not need to mention the name of the invoked method Good rule of thumb: the test name should include an explicit expectation Use verbs such as should, does, returns, throws, etc. @Test public void doNotCountOutOfStockItem() {   Product p = new Product();   p.setAvailable(false);   ShoppingCart cart = new ShoppingCart();   cart.addItem(p);   assertEquals(0, p.numItems()); } Author: Gal Lalouche - Technion 2015 ©

JUnit – Exceptions A test that throws an exception will fail. So how do we make sure a code throws an exception when it should? We would like to verify 3 things: The right exception has been thrown The right line has thrown the exception (sometimes) The exception contains the right data (rarely) Author: Gal Lalouche - Technion 2015 © Do we always care about the message?

JUnit – Exceptions The hard way – Using the try/catch pattern  Verifies our 3 wishes  Easy to forget the fail resulting in a test that never fails  Quite long and verbose Test code is just as important as our “regular” code! We want to minimize code duplication and boilerplate. @Test public void badEncodeArgument() { Encoder encoder = new Encoder(“UTF-8”); try { encoder.encode(null); fail(“Exception should have been thrown”); } catch (NullPointerException e) { assertEquals(“Text should not be null”, e.getMessage()); } Author: Gal Lalouche - Technion 2015 © Test code is just as important as our regular code! We want to minimize Based on http://alexruiz.developerblogs.com/?p=1530

JUnit – Exceptions The easy way (JUnit 4.0) – expected value in @Test annotation  Can’t check the exception message  Can’t verify which line has thrown the exception  Very short Can be “good enough” in most cases @Test(expected = IllegalArgumentException.class) public void badEncodeArgument() { Encoder encoder = new Encoder(“UTF-8”); encoder.encode(null); } Author: Gal Lalouche - Technion 2015 © Based on http://alexruiz.developerblogs.com/?p=1530

JUnit – Exceptions The smart way (JUnit 4.7) – Using @Rule annotation and ExpectedException  Verifies our 3 wishes  Still quite short JUnit Rules offers a few additional candies @Rule public ExpectedException thrown = ExceptedException.none(); @Test public void badEncodeArgument() { Encoder encoder = new Encoder(“UTF-8”); thrown.expect(NullPointerException.class); thrown.expectMessage(“Text should not be null”); encoder.encode(null); } Author: Gal Lalouche - Technion 2015 © Do we need to reset rule after every test? why/why not? Based on http://alexruiz.developerblogs.com/?p=1530

JUnit - Timeout We want to verify that our code finishes in the allotted time. This is criminally verbose @Test public void testTimeout() { final boolean[] done = new boolean[] { false }; new Timer().schedule(new TimerTask() { @Override public void run() { foo(); done[0] = true; } }, 0); Thread.sleep(10); if (done[0] == false) fail(“Failed to run in the allotted time"); Author: Gal Lalouche - Technion 2015 © Why do we have to use an array? Why can’t we use lambdas? If foo throws an exception we have to catch it in the runnable, making the code even more verbose

JUnit - Timeout In JUnit 4.0 – Use the timeout annotation value Test will fail after 10 milliseconds. Global timeouts using @Rule (JUnit 4.7) @Test(timeout = 10) public void testTimeout() { // Tested code } Author: Gal Lalouche - Technion 2015 © @Rule public MethodRule globalTimeout = new Timeout(10); @Test public void test1() { // Tested code } public void test2() { Defines a timeout constraint for every test

JUnit – Ignoring tests You can ignore tests using the @Ignore annotation Test will not run, but will still be visible in the test reports Commented out tests will usually be forgotten about Won’t be deleted and possibly will not be fixed Ignored tests are easily visible in the output window Make sure you disable tests temporarily Bad tests should either be deleted or fixed Ask yourself – why are you ignoring the test in the first place? Author: Gal Lalouche - Technion 2015 ©

JUnit - Running Textual runner IDE Support Used mainly in command line environments (Scripts, Maven, Ant, CI) IDE Support To run several test cases org.junit.runner.JUnitCore.runClasses(TestCase1.class, ...); Author: Gal Lalouche - Technion 2015 © @RunWith(Suite.class) @Suite.SuiteClasses({ TestCase1.class, TestCase2.class, subpackage.AllTests.class, …}) public class AllTests {} We can see that we have a hierarchy of test suites. We can run only a sub-tree of the tests We have one ignored test

JUnit – Source code Organization Option 1: Test class in same folder as subject A single hierarchy of folders Locality Option 2: Keep tests in the mirrored directory structure of source location A duplicated hierarchy of folders Easy to find all tests Easy to separate source code from its tests Easier bytecode separation Author: Gal Lalouche - Technion 2015 © Maven default is option #2, but it can also be configured differently

Testing – Leveraging OOP Tests are classes too! Can use inheritance to our advantage Use Abstract Test classes against abstract classes / interfaces Classes Tests Class A ATest Author: Gal Lalouche - Technion 2015 © B C BTest CTest

Testing – Leveraging OOP public abstract class Stack<T> { public void push(T element); public int size(); } public class ArrayStack<T> extends Stack<T> { // … implementation code public class LinkedListStackStack<T> extends Stack<T> { Author: Gal Lalouche - Technion 2015 ©

Testing – Leveraging OOP public abstract class StackTest { private final Stack<Object> stack;   protected StackTest(Stack<Object> stack) { this.stack = stack; } @Test public void sizeIsOneAfterOnePush() { stack.push(new Object()); Assert.assertEquals(1, stack.size()); Author: Gal Lalouche - Technion 2015 ©

Testing – Leveraging OOP Extend abstract TC to initialize the concrete test subjects public class ArrayStackTest extends StackTest {   public ArrayStackTest() { super(new ArrayStack<Object>()); } // specific ArrayStack tests Author: Gal Lalouche - Technion 2015 © public class LinkedListStackTest extends StackTest {   public LinkedListStackTest() { super(new LinkedListStack<Object>()); } // specific LinkedListStackTest tests

Testing – Order (or lack thereof) Do not assume order between tests There’s no order guaranties in TestCases There is one in TestSuites Avoid side effects in tests public class StackTest {   private static Stack<Object> s = new Stack<>(); @Test public void pushFirstAndCheckSize() { s.push(new Object()); assertEquals(1,s.size()); } public void pushSecondAndCheckSize() { assertEquals(2,s.size()); Author: Gal Lalouche - Technion 2015 © Bad !

Testing – Resource Management Do not load data from hard-coded locations on a file system Use Class.getResource() or Class.getResourceAsStream() Will search the file relatively to the Test Case .class file Maven will automatically create a src & test resource folders @Before public void setUp () { InputStream inp = FileInputStream("C:\\TestData\\dataSet1.dat"); … } @Before public void setUp () { InputStream inp = getClass().getResourceAsStream("dataSet1.dat"); … } Author: Gal Lalouche - Technion 2015 © “Do not load data from hard-coded locations on a file system” why not? This works great with maven’s resource folders

Unit Testing: What to Test It is not practical to test everything: State space > 2 #𝑎𝑟𝑔𝑢𝑚𝑒𝑛𝑡𝑠+#𝑚𝑒𝑚𝑏𝑒𝑟𝑠 ⇒ Not always practical Loops in the code ⇒ State space is infinite / Halting Problem End to End and Acceptance tests will cover the state space quite well Cover as much of the code as possible, but be smart about it Extensiveness of the test should be proportional to the complexity of the implementation of the tested method If m2() calls m1(), no need to duplicate m1() tests for m2() But, for each variation in the flow (usually an if()) you should have a corresponding test that exercises it Always test public methods Should you test package-private and protected methods as well? Private methods usage is important only in the context public methods If you find yourself wanting to test a private method, you should rethink your design, (e.g., extract the private method to a helper class) Author: Gal Lalouche - Technion 2015 ©

Unit Testing: Quality Cover code usage Code Coverage Check common usage errors / edge cases: nulls empty strings zeros empty lists single-item lists uninitialized objects bad configurations Exception handling Code Coverage Function, Statement, Branch, Decision coverage Monitor using external Code Coverage tools (e.g. EclEmma) Author: Gal Lalouche - Technion 2015 ©

Code Coverage - EclEmma Author: Gal Lalouche - Technion 2015 © A plugin for eclipse

Code Coverage Code coverage is correlated with good testing, but does not equate it You can achieve very high coverage with bad tests (e.g., testing without asserts) You can write great tests with low coverage 100% coverage may look “pretty”, but should not be a goal in and off itself You should always suspect tests that were written solely for achieving high coverage Do you really need to test for NullPointerException for each of your parameters? You can use code coverage to Spartanize your code e.g., branches that are never taken may be dead code Author: Gal Lalouche - Technion 2015 ©

Testing – Do’s & Don’ts Mutability makes code harder to test Tests also have to take state into account Always place shortest, simplest tests first in a TestCase or in a TestSuite You should always make sure the simplest cases work before you carry on to the complicated ones Prefer lots of short tests instead of a few long ones Every test should test a single behavior Speed up discovery-to-fix cycle Testing code should be simpler than the subject code Complicated tests usually implies complicated production code usage Tests are the code usage examples Do not put if statements in your tests. Loops are quite rare. Author: Gal Lalouche - Technion 2015 ©

Testing – Do’s & Don’ts Always make sure you start Green before you start coding This way, you know if you broke something Unless working in TDD… In which case, start Green before refactoring! Regression testing Make sure new additions don’t break existing code Run tests as often as possible The earlier you detect the bug the sooner you solve it and the easier it becomes Therefore, test runs should be short, at most 10ms per test Never commit code that doesn’t pass all tests! Author: Gal Lalouche - Technion 2015 ©

Testing – Do’s & Don’ts You can actually debug using unit tests! When you work on a bug, write a test case first Your work is done when the test case succeeds If you write the test after the bug is fixed, you cannot know if the test succeeded in reproducing the bug Helps with regression testing, i.e., ensuring the bug won’t reappear later You can actually debug using unit tests! Write a test that fails If you still aren’t sure what the bug is, write a smaller unit test that fails Repeat step 2 as necessary This could be preferable to running a debugger, as the tests remain when done Author: Gal Lalouche - Technion 2015 ©

Testing – Do’s & Don’ts Hard to test? ⇒ Re-think the design! When you change the subject class, add tests Testing is meant to improve the quality of the code Do not write bad code to pass tests !! Although possible in TDD… Do not write bad tests to pass tests !! (Make sure a test can fail) Hard to test? ⇒ Re-think the design! Author: Gal Lalouche - Technion 2015 ©

Test types – misc. (not taught this semester) Behavior-driven development Using Domain Specific Language (DSL) to structure tests around stories and features Property tests Large randomized input to check invariants and properties of output Mutability testing Changing (mutating) the source code or tests slightly, to see if our tests fail This ensures tight coupling between tests and source code Design by Contract Asserting pre and post-conditions on class’s methods Fails in runtime, possible to check even at compile time Author: Gal Lalouche - Technion 2015 © Single elements does not imply a single class In the next tutorial we will discuss how to avoid writing integration tests when testing elements that are dependent on other elements