slide 1 ee417: web application development lecturer: david molloy room: xg19 mondays 10am-1pm notes:...

24
Slide 1 EE417: Web Application Development Lecturer: David Molloy Room: XG19 Mondays 10am-1pm Notes: http://ee417.eeng.dcu.ie Mailing List: ee417@list. dcu.ie

Upload: ruby-owen

Post on 24-Dec-2015

220 views

Category:

Documents


2 download

TRANSCRIPT

Slide 1

EE417: Web Application Development

Lecturer: David Molloy

Room: XG19 Mondays 10am-1pm

Notes: http://ee417.eeng.dcu.ie

Mailing List: ee417@list. dcu.ie

Slide 2

Testing

• Software testing is a process used to verify that software:

1.Works as expected2.Fulfils the specified design requirements3.Satisfies the end-product customers

•ANSI/IEEE 1059 Standard, testing is defined as:"A process of analysing a software item to detect the differences between existing and required conditions (that is defects/errors/bugs) and to evaluate the features of the software item.“

•Different individuals responsible for testing- Software Testers (dedicated)- Software Developers (unit tests)- Project Managers/Leads (general testing)- End Users (usability/compatibility testing)

Slide 3

Types of Testing

• Unit Testing – testing small components (units) of code. Covered in this section

• Functional Testing – testing of software functions as a “black box” by

feeding inputs and examining outputs

• Integration Testing – combining of small modules (previously unit tested) and testing outputs from a combined group

• Usability Testing – how usable are developed systems and what are customer experiences. Is the system likeable / user-friendly?

• Compatability Testing – how does the system behave user different operating systems, under different browsers or devices?

Slide 4

Unit Testing

Slide 4

• Unit tests allow us to verify that small sections of code are working

• “Units” are intended to be the smallest testable part of an application

and would generally be code in a method/function

• Tests are written by developers to ensure that code meets design specifications and behaves as intended

• Developers typically write tests into every single small component of code that they write!

• Seems to present a large overhead compared to traditional coding

• Why do it then?

Slide 5Slide 5

Unit Testing – Why?

Slide 5

1. Debugging ProblemsBy writing unit tests, we create an agreement of what the code must satisfy. When we run our tests at a later stage, every single unit test is testing simultaneously.

-> Not only help debug problems, but will often prevent their occurrence in the first place!

2. Change ManagementIn the vast majority of companies, developers will be working in teams on common sets of code. Developers are in a position where they can adversely affect other programmers by changing shared code.

Consider the following diagram, showing how a change in an API class could adversely affect others.

Slide 6Slide 6Slide 6

Change Management

Slide 6

BLUE Programmer makes a change, which breaks pre-written code from ORANGE Programmer

Unit Tests typically prevent this, as each developer is aware of the “contract” that the code must adhere to. If all coders follow this contract and BLUE subsequently breaks this contract, this will be immediately picked up by unit testing!

Slide 7Slide 7Slide 7

Unit Testing – Why?

Slide 7

3. Documentation

By using unit testing, developers essentially create a dynamic, ever-changing set of documentation for the code of a system.

Developers can use these tests to get a clearer understanding of the expected operation of each small function.

Often an improvement over other forms of documentation, particularly where such documentation has not been kept up to date.

Slide 8Slide 8Slide 8Slide 8

Junit

Slide 8

• Junit is a unit testing framework for the Java programming language

• Open Source

• Allows us to write and run repeatable tests and build test suites

• Tests can be run manually or continuously (with immediate results) meaning problems are identified and remedied quickly

• Integrated with common IDEs including Eclipse

• Download from junit.org

• Download:- junit-x.yy.jar (core JUnit jar)

- hamcrest-core-x.y.jar (framework to help writing tests)

• Add these JAR files to our CLASSPATH in environment variables

Slide 9Slide 9Slide 9Slide 9

Our First Test Class

Slide 9

import org.junit.Test; import static org.junit.Assert.assertEquals;

public class MyTest { @Test public void firstTest() { System.out.println("MyTest: Inside firstTest()"); String str= "First Test Passed"; assertEquals("First Test Passed",str); } }

•Can compile using: javac MyTest.java

•Can’t run just yet though. No main method!

•Let us create a “runner” class to run our tests!

MyTest.java

Slide 10Slide 10Slide 10Slide 10Slide 10

Our First Test Class

Slide 10

import org.junit.runner.*; import org.junit.runner.notification.Failure;

public class MyTestRunner { public static void main(String[] args) { Result result = JUnitCore.runClasses(MyTest.class); for (Failure failure : result.getFailures()) { System.out.println(failure.toString()); } System.out.println("Tests Successful = " + result.wasSuccessful()); } }

•javac MyTestRunner.java•Java MyTestRunner

Tests Successful = true

•We have just written our first unit test!

MyTestRunner.java

Slide 11Slide 11Slide 11Slide 11Slide 11Slide 11

Example #1 – PrimeTester

Slide 11

• Purpose of the code is to take an argument and determine whether it is a prime number or not

• "An integer greater than one is called a prime number if its only positive divisors (factors) are one and itself. “

import java.math.BigInteger;class CheckPrime { public static void main(String[] args) { System.out.println("Welcome to TestPrime"); if (args.length!=1) { System.out.println("Please provide a number, in the format: java

CheckPrime 15"); System.exit(0); } else { System.out.println("Your inputted number is " + args[0]); System.out.println("Prime: " + isPrimeMethod(args[0])); } } public static boolean isPrimeMethod(String s) { BigInteger i = new BigInteger(s); return i.isProbablePrime(1); } }

Slide 12Slide 12Slide 12Slide 12Slide 12Slide 12Slide 12

Example #1 – PrimeTester

Slide 12

1. Describe a scenario where the method ‘isPrimeMethodx(String s)’ will fail

2. Create a test class ‘PrimeTest.java’ which will test this scenario and report a failure

3. Fix the code in CheckPrime.java so that this test is satisfied

Notes: • The following PrimeTestRunner.java file has been provided.

• You can assume that the value of "isProbablePrime(certainty)" method will be accurate. In reality this is quite a complex method, which allows a trade-off of speed vs accuracy using various mathematical algorithms.

Slide 12

Slide 13Slide 13Slide 13Slide 13Slide 13Slide 13Slide 13Slide 13

Example #1 – PrimeTester

Slide 13

Provided: PrimeTestRunner.java

import org.junit.runner.*; import org.junit.runner.notification.Failure;

public class PrimeTestRunner { public static void main(String[] args) { Result result = JUnitCore.runClasses(PrimeTest.class); for (Failure failure : result.getFailures()) { System.out.println("Test Failure: " + failure.toString()); } System.out.println("Tests Successful = " + result.wasSuccessful()); } }

Slide 13

Slide 14Slide 14Slide 14Slide 14Slide 14Slide 14Slide 14Slide 14Slide 14

Solution

Slide 14

1. The isPrimeMethod(String s) method will fail if the passed String cannot be converted to an integer

2. We create our tester class to test for a numeric scenario and a non numeric scenario: PrimeTest.java

import org.junit.Test; import static org.junit.Assert.assertEquals;

public class PrimeTest { @Test public void testPrimeNumeric() { System.out.println("PrimeTest: testPrimeNumeric()"); assertEquals(true,CheckPrime.isPrimeMethod("5")); }

@Test public void testPrimeNonNumeric() { System.out.println("PrimeTest: testPrimeNonNumeric()"); assertEquals(false,CheckPrime.isPrimeMethod("a")); } }

Slide 14

Slide 15Slide 15Slide 15Slide 15Slide 15Slide 15Slide 15Slide 15Slide 15Slide 15

Solution

Slide 15

• We could run this test now and we should see that the non numeric test fails, with the following output (as requested):

• Final Step – Fix the code so that all tests pass

Slide 15

Slide 16Slide 16Slide 16Slide 16Slide 16Slide 16Slide 16Slide 16Slide 16Slide 16Slide 16

Solution – New CheckPrime.java

Slide 16Slid 16

import java.math.BigInteger;

class CheckPrime { public static void main(String[] args) { System.out.println("Welcome to TestPrime"); if (args.length!=1) { System.out.println("Please provide a number, in the format: java CheckPrime 15"); System.exit(0); } else { System.out.println("Your inputted number is " + args[0]); System.out.println("Prime: " + isPrimeMethod(args[0])); } } public static boolean isPrimeMethod(String s) { try { BigInteger i = new BigInteger(s); return i.isProbablePrime(1); } catch (NumberFormatException e) { return false; } }}

Slide 17Slide 17Slide 17Slide 17Slide 17Slide 17Slide 17Slide 17Slide 17Slide 17Slide 17

When to test? How small are units?

Slide 17

•When we write tests, we are testing our code and not the compiler

•For example, should we test get() and set() methods in our Javabeans?

public class User { private String firstname; private String surname;

public User(String firstname, String surname) { this.firstname = firstname; this.surname = surname; } public String getFirstname() { return firstname; } public void setFirstname(String firstname) { this.firstname = firstname; } public String getSurname() { return surname; } public void setSurname(String surname) { this.surname = sur

Slide 17

Slide 18Slide 18Slide 18Slide 18Slide 18Slide 18Slide 18Slide 18Slide 18Slide 18

When to test?

Slide 18

• Let’s create a basic test class for testing a JavaBean:

import org.junit.Test; import static org.junit.Assert.assertEquals;

public class UserTest { @Test public void testGetSetFirstname() { System.out.println("UserTest: Inside testGetSetFirstname()"); User user = new User(); user.setFirstname("David"); assertEquals("David", user.getFirstname()); }}

• We can run this in a usual way by creating a TestRunner and running this test

Result result = JUnitCore.runClasses(UserTest.class);

• What have we actually tested here?

Slide 18

Slide 19Slide 19Slide 19Slide 19Slide 19Slide 19Slide 19Slide 19Slide 19Slide 19Slide 19

When to test?

Slide 19

• Consider our method in a shorter form:

public void testGetSetFirstname() { firstname = "David"; assertEquals("David", firstname);}

• .... And in an even shorter form...

public void testGetSetFirstname() { assertEquals("David", "David");}

• All we are really achieving in our test method is that we are testing the compiler! This is not our job (it is Oracle’s job in fact!)

• Unit tests are designed to identify scenarios where something might breek! If you have written code that might break, then it is appropriate to add in a unit test.

• So, for example, a test might be appropriate on a constructor where some additional business logic was being performed.

Let’s take an example of this!Slide 19

Slide 20Slide 20Slide 20Slide 20Slide 20Slide 20Slide 20Slide 20Slide 20Slide 20Slide 20

Test Example – ‘Client.java’

Slide 20

public class Client { private String firstname; private String surname; private String initials;

public Client() {}

public Client(String firstname, String surname) { this.firstname = firstname; this.surname = surname;

this.initials = firstname.substring(0,1) + surname.substring(0,1); } public String getFirstname() { return firstname; } public void setFirstname(String firstname) { this.firstname = firstname; } public String getSurname() { return surname; } public void setSurname(String surname) { this.surname = surname; }

public void setInitials(String initials) { this.initials = initials;

} public String getInitials() {

return initials;}

} Slide 20

Slide 21Slide 21Slide 21Slide 21Slide 21Slide 21Slide 21Slide 21Slide 21Slide 21Slide 21Slide 21

Test Example – ‘Client.java’

Slide 21

•Want to test the core code, marked in yellow on previous slide

•Some scenarios where this might either success or fail:

1.Firstname ‘David’, Lastname ‘Molloy’ -> ‘DM’ -> Success2.Firstname ‘’, Lastname: ‘Molloy’ -> RunTime Error -> Fail (why?)3.Firstname ‘David’, Lastname:null > RunTime Error -> Fail (why?).... Etc..

•RunTime exceptions occur when the application is running and not at compilation time (making them far more problematic!)

•Will occur in some scenarios but not in others

•How should we fix this code?- Write code, some ad-hoc testing and consider it working (not a formal testing approach but very common)- Write the production code, then write formal tests and ensure

they pass (like in our PrimeTest example)- Test Driven Development

Slide 22Slide 22Slide 22Slide 22Slide 22Slide 22Slide 22Slide 22Slide 22Slide 22Slide 22Slide 22Slide 22

Test Driven Development

Slide 22

•Fundamentally different approach, focused around ‘test-first development’ where the developer writes tests before writing any production code!

•Encourages the developer to think through the design requirements of the software system before writing the actual implementation code

1.Developer writes a test to define some functionality/business logic2.The test should fail as we have no business logic code initially3.The developer now writes the minimal amount of code to pass the test. Code does not need to be elegant4.All of the tests to date are run again - Test succeeds : Code meets the requirements - Test fails: Back to step 3 to modify the code5.Code can be cleaned up, made elegant, comments added. This is our final production code!

Slide 23Slide 23Slide 23Slide 23Slide 23Slide 23Slide 23Slide 23Slide 23Slide 23Slide 23Slide 23Slide 23Slide 23

Test Driven Development

Slide 23

Slide 24Slide 24Slide 24Slide 24Slide 24Slide 24Slide 24Slide 24Slide 24Slide 24Slide 24Slide 24

Test Example – ‘Client.java’

Slide 24

The ‘Test-Driven Development’ steps

1.Start with blank ‘Client.java’ with no initials business logic (Client.java)2.Write our first test. Let us do the standard one where both firstname and surname are provided (ClientTest.java)3.Create our RunnerClass (ClientTestRunner.java) and run the test. Test FAILS -> Expected4.Now edit ‘Client.java’ to make the code work in this scenario5.Run the test again (ClientTestRunner.java) Test PASSES -> Expected6.No real code cleanup to do. We have our production code which passes this test.7.Now we test for the scenario where the firstname is null or the surname is null. First write the test (ClientTest.java)8.Run our ClientTestRunner.java Test FAILS -> Expected9.Fix ‘Client.java’ and run the test again Test PASSES -> Expected10.Now we test for the scenario where the firstname is blank or the surname is blank. First write the test (ClientTest.java)11.Run our ClientTestRunner.java Test FAILS -> Expected12.Fix ‘Client.java’ and run the test again Test PASSES -> Expected

-> Fully functional (but time intensive) code!

Slide 24