An integrated approach to testing is described which includes both static and dynamic analysis methods and which is based on theoretical results that prove both its effectiveness and efficiency. Programs are viewed as consisting of collections of functions that are joined together using elementary functional forms or complex functional structures. Functional testing is identified as the input-output analysis of functional forms. Classes of faults are defined for these forms, and results are presented which prove the fault-revealing effectiveness of well defined sets of tests. Functional analysis is identified as the analysis of the sequences of operators, functions, and data type transformations which occur in functional structures. Theoretical results are presented which prove that it is only necessary to look at interfaces between pairs of operators and data type transformations in order to detect the presence of operator or data type sequencing errors. The results depend on the definition of normal forms for operator and data type sequencing diagrams.