Download Slide 20

Survey
yes no Was this document useful for you?
   Thank you for your participation!

* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project

Document related concepts
no text concepts found
Transcript
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 1
Testing
• Software testing is a process used to verify that software:
1. Works as expected
2. Fulfils the specified design requirements
3. 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 2
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 3
Unit Testing
• 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 4
Unit Testing – Why?
1. Debugging Problems
By 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 Management
In 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 5
Change Management
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 6
Unit Testing – Why?
3. Documentation
By using unit testing, developers essentially create a dynamic, everchanging 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 7
Junit
• 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 8
Our First Test Class
MyTest.java
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!
Slide 9
Our First Test Class
MyTestRunner.java
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!
Slide 10
Example #1 – PrimeTester
• 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 11
Example #1 – PrimeTester
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
Example #1 – PrimeTester
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
Solution
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
Solution
• 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
Solution – New CheckPrime.java
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
Slid 16
When to test? How small are units?
• 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
When to test?
• 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
When to test?
• 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
Test Example – ‘Client.java’
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
Test Example – ‘Client.java’
• 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’ -> Success
2. 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 21
Test Driven Development
• 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 logic
2. The test should fail as we have no business logic code initially
3. The developer now writes the minimal amount of code to pass the
test. Code does not need to be elegant
4. All of the tests to date are run again
- Test succeeds : Code meets the requirements
- Test fails: Back to step 3 to modify the code
5. Code can be cleaned up, made elegant, comments added. This is our
final production code!
Slide 22
Test Driven Development
Slide 23
Test Example – ‘Client.java’
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 -> Expected
4. Now edit ‘Client.java’ to make the code work in this scenario
5. Run the test again (ClientTestRunner.java) Test PASSES ->
Expected
6. 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 -> Expected
9. Fix ‘Client.java’ and run the test again
Test PASSES -> Expected
10.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 -> Expected
12.Fix ‘Client.java’ and run the test again
Test PASSES -> Expected
-> Fully functional (but time intensive) code!
Slide 24