name: inverse layout: true class: taylor msoe --- class: center, middle .title[ # Verification and Validation ] ??? * **P** speaker view * **C** clone slideshow * **?** help --- # Verification and Validation * Validation — checking if the software (end product) has met the client's true needs and expectations. -- * SWE 3411 - Software Requirements and Architecture, taken by software engineering students (elective for computer engineering and computer science students) -- * Verification — determining if the software is designed and developed as per the specified requirements. -- * SWE 2721 - Introduction to Software Verification, taken by software engineering students (elective for computer science students) --- # Levels of Testing * Acceptance testing — ask client if software meets expectations -- * System testing — testing on the system it is intended to run on -- * Integration testing — testing the integration across multiple software units -- * Unit testing — testing the smallest possible piece of software --- # Automating Tests * We often write software to automate mundane tasks -- * We can automate testing with code -- * Unit testing is easiest to automate -- * Acceptance testing cannot be automated --- # Pre- and Post-Conditions * When testing a method we need to ensure that, given an initial condition, calling a method will result in the expected resulting condition -- * Precondition — the initial condition -- * Postcondition — the expected condition resulting from calling the method -- * To run unit tests we need a driver program that: + Creates an object + Ensures the precondition + Calls the method + Verifies the expected postcondition --- # JUnit Platform * The JUnit Platform contains the **jupiter** testing framework to help automate unit testing -- * JUnit 5 is annotation based — uses annotations to control test program flow -- * Annotations define exectution order, identify tests, etc... -- ``` import org.junit.jupiter.api.*; ``` -- * Often tests use **Assertions** to test whether a test passes -- ``` import org.junit.jupiter.api.Assertions.*; ``` --- # Annotations | Annotation | Description | | ---------- | ----------- | | `@Test` | Method is considered a test method | | `@BeforeEach` | Method runs before each test method | | `@AfterEach` | Method runs after each test method | | `@BeforeAll` | Method runs before all test methods | | `@AfterAll` | Method runs after all test methods | | `@Disable` | Method is ignored | --- # Assertions ``` assertTrue(list.isEmpty(), "Optional failure message"); assertFalse(list.isEmpty(), "Optional failure message"); assertNull(list.get(0), "Expecting null"); assertNotNull(list.get(0), "Did not expect null"); // assertEquals(expected, actual, message) assertEquals(0, list.size(), "Optional failure message"); assertNotEquals(0, list.size(), "Optional failure message"); // assertThrows(exceptionType.class, lambdaWithMethodCall, message) assertThrows(IndexOutOfBoundsException.class, () -> list.add(-1, null)); ``` --- # Black-box and White-box Testing * Black-box test — tests an item based on its public interface and functional requirements -- * White-box test — tests an item using knowledge of the internal structure of the item --- # Why Write Unit Tests? * Protect code from inadvertent breaking changes when other features added -- * Helps clarify how each component is intended to operate -- * Writing tests before implementing a method can result in simplified implementations -- * Motivation behind Test-Driven Development (TDD) + Write a test case for a feature + Run the test and observe that it fails (but other tests still pass) + Do minimal implementation to make the test pass + Repeat for next feature