del.pdf
Document Details
Uploaded by AdvancedArithmetic
Tags
Full Transcript
Week 5 Visualising software architecture and code. Software architecture: high level structure of system (“blueprint” for system and project) Defines major components, their relationships and interactions The principles guiding their design and evolution Builds a shared understanding...
Week 5 Visualising software architecture and code. Software architecture: high level structure of system (“blueprint” for system and project) Defines major components, their relationships and interactions The principles guiding their design and evolution Builds a shared understanding for the team Ensures team understands the context of the components they build Agile projects favor code over documentation but does NOT mean no documentation Ned “just enough” software architecture design (lightweight and accessible to different stakeholders) Architecture represents significant design decisions Software architectural patterns e.g. monolith vs microservices architectures Separation of GUIs from business and backend logic e.g. Model-View-Controller vs Model-VIew-View Model C4 Model: framework for visualizing architecture of a software system via a hierarchical set of diagrams. “Abstraction-first” approach: principle of starting with high-level abstractions before diving into details. Each diagram is at a different abstraction level and intended for different stakeholders. 4 levels (Context, Containers, Components and Code) Context: high level overview of the environment which system operates (e.g. users, other systems, external services). Typically these are other system outside scope of ur system, no responsibility or ownership, System is a single box. High level of abstraction; accessible for non technical team members. Containers: parts that make up the system (applications, services, db… these are what you build) Containers are (potentially) separating running processes that execute/store data. (note: these containers are in ONE diagram) Depicts “high level shape” of system and major technology choices. Meant for technical people inside n outside of software development team (software architects, developers, operations and support staff) Components: building blocks that make up a container.it is the internal structure (e.g. structure of a single app) Components are typically packaged together (e.g. in a single application) Meant for software architects and developers. Optional diagram, only if it adds value. Code: inside the components, visualize implementation of component (e.g. classes and methods of object oriented code) Utilize existing notations: Unified modeling language for modeling code Entity relationship diagram for modeling relational databases Agile teams create these models more sparingly. Focus on particularly complex relations among object oriented classes Does not show deployment just system architecture! Optional diagram E.g. Integrated Billing for hospitals. They have multiple completely separate legacy systems for different patient costs, e.g. - A legacy pharmacy billing system - A legacy ward billing system. Your team is developing a modern web application that allows all of these costs to be retrieved and consolidated in a single place C1 C2 C3 UML Class Diagrams for Object Oriented Design UML notations Category Diagram Usage Structural Class Diagram Describes static structure of object-oriented software. Built from classes & relationships between them Object diagram Characterize class diagram, usually represents object combinations of specific class diagram Component Depicts physical organization of software assets that diagram would provide required functionality Deployment Shows how software is deployed to production diagram Behavioral Use Case Depict actors, use cases (description of functionality) diagram and relationships. Sequence Models dynamic aspects of classes. Depicts objects and diagram interactions through time-ordered messages. Temporal view Collaboration Same as sequence diagram but emphasizes structural diagram organization of objects Statechart Expresses life cycle of an object or a system diagram Activity diagram An elaborate form of flow chart diagrams. Depicts flow of activities in a system UML Class diagrams : describe static structure of object oriented code E.g. attributes/methods of classes and relationships between objects. Use class diagrams to visualize: o Data abstraction and encapsulation ▪ Data abstraction: simplifying complex systems by modeling classes based on essential characteristics while hiding unnecessary details. Implemented through classes (“template”) and “instances” of the “template” is called an object ▪ Encapsulation: bundling of data and function (methods) that operate on it within the same class The special method :”_init_” is (roughly) a constructor o Association relationships : represent connections between classes (e.g. the ways in which their objects may interact) ▪ Multiplicity (one to one, one to many, many to many etc.) ▪ Directionality (uni or bidirectional) ▪ For “whole part” r/s between objects (there are 2 special types of association) Aggregation - “x has a y” but x and y can exist independently o E.g. “a person has a pet” person & pet can exist independently o Represented by a hollow diamond Composition - “x consists of y” ; y cannot exist independently o E.g. “house consists of rooms” o Once x is destroyed, y is also gone but can destroy y (room) and x(house) will still exist, o Represented by a shaded diamond o Inheritance and polymorphism ▪ Inheritance : allows a new class (subclass) to derive attributes or methods from an existing class (superclass) ”is-a” relationships e.g. “Manager is a staff” Allows for code reuse and creation of hierarchical relationships ▪ Polymorphism : allows for many forms of same method, depending on the type of object (i.e. which class in the hierarchy it was instantiated from) Basically, the same method but implemented differently When u do polymorphism, inheritance must be there first Example briefing (partial) - GP surgery system “All charges will be handled electronically. Each patient will have an “e-wallet” that they can top up and use to spend on consultations.” “During a consultation, the doctor enters details such as the diagnosis and prescription. At the end of the consultation, the details are submitted, and the patient’s e-wallet is deducted according to the consultation length and the doctor’s hourly rate.” How to decide whether to create a class or not? o What are the attributes that are important in this class? What are the functions I can use in the class and will be required as part of development? o If u have multiple attributes u MAY want to create a class o e.g. if u want to create a class for payment: u can create (consists of multiple attributes: every payment u need to know the payment amount, currency, payment method OR under the consultation class can include payment then don't need a separate class for payment o “Length” cannot be a class. if u hv a consultation class - u can indicate what is the length. C1 context diag: patient, doctor, legacy sys (may or may not hv a legacy sys) and stripe C2 container diag: zoom into what is in ur sys - frontend, api, db - containers can be deployed separately C3 component diag: zoom into API app (authentication, consultation mgmt and e-wallet - and each of these will need to call eo) - components are not deployed separately C4 code Week 6 Automated Testing Why automate tests? Repeatable and one click Early feedback Safety for refactoring Tool support Automated Testing Pyramid End to end testing : test the integrated flow of the application from start to finish, simulating real user scenarios. Verify that all subsystems work together correctly. (More “realistic” tested and slower) Integration Testing : multiple components (modules) of a system are tested together. Check if the components correctly integrate with db Unit testing : testing individual “units” (functions/classes) are tested in isolation (without executing other functions, db…) (Faster, more reliable, smaller scope) However, do take note: the scope of the tests does not equate to how much time is spent on testing The scope of these tests are different and they complement each other. e2e testing will only tell u whether requirements are delivered, wont tell u which line of code is causing the issue that's why u need unit testing and integration testing. If-else statements for boundary tests should be captured for your unit test. Designing tests: Black Box or White box? Design tests based on inputs/outputs.Does not consider implementation. Focuses on observed behavior rather than internal workings of the code. Works well with users: they don’t care about implementation, just the input and output. Take the implementation of functions into consideration when designing. Ensure that all internal paths, branches and conditional statements are working correctly. E2E testing is the highest level. Only require black box testing as it would have captured all errors etc. in the other tests (unit and integration test). FIRST principles of testing:expected qualities of automated tests F-ast : production system have a lot of such tests, will need to be fast I-solated: should be able to execute tests in any order (test should not fail because another test was run first) R-epeatable: executing same test multiple times should not change outcome otherwise it is a flaky test S-elf validating : test cases should determine their outcome by using assertions. (no manual inspection requireD) T-imely: can be written anytime (even before implementing function) Frameworks for writing tests Instead of ad hoc assert statements, we typically use testing frameworks o Test runners: automate process to execute functions nonstop n collecting outcomes o Automated test discovery - don’t want to have to keep indicating which pt of the code should this test o Test fixtures help with the isolation allow us to define functions operated before and after every test, restore data state Unit & integration tests in python use “unittest” or “pytest” o Other languages can use Junit, Nunit, MStest, etc… End to end testing can consider selenium, cypress or netflix safe test Test driven development Build test first then fail the test and then refactor code to pass the test Test first then test automation Goal: ‘clean code that works’ Challenges of TDD: Management support Code with dependencies are difficult to unit test Test Design and management Typical process of using unittest for testing Design test cases that will test the testable properties of the class Build TestCase classes that contain test methods that implement the test cases In the test methods, introduce assertions to test the expected vs actual test results Build class under test to ‘pass’ the test cases The method self.assertEqual() - compares two values. If you’re expecting an exception to be raised, you want to test actively using self.assertRaises(). Allows u to catch and ascertain an exception is being raised. self.assertRaises(Exception, Method_ure_gg_to_Call, arguments) Negative Test: If the test fails (resulting in an AssertionError), it indicates that an exception was expected but not raised. This means that the form should have triggered an error when the withdrawal condition was met, but it did not So you go back and edit your class to include a condition. if xxx: xxx else: raise Exception (“warning”) If an exception is raised when you are expecting it, the test case will pass. Coverage - it's not the quantity that matters but how effective it is Test coverage: measures how much of the code base has been exercised by your test suite o Types: ▪ Statement coverage: % of executable statements that have been executed ▪ Branch coverage: % of decision branches (if-else has been executed) ▪ Function coverage - % of functions/methods that have been called at least once o Increasing coverage helps ensure a larger portion of the codebase is tested o BUT high coverage e.g. 100% does NOT mean that the test suite is effective !!! it only shows that you have tested for every single part of the code. Does not mean that the test is 100% correct and will catch every bug.Look at the structure of the code and consider edge cases. 100% function coverage :Have 2 functions to cover, both have been called in the test suite. 100% branch coverage : Branch coverage needs to look inside the code and look for while loops and conditions. Then if you look at the tests do you have test cases that make the condition at least true once and at least false once. 100% statement coverage : all of the statements are executed at least once If price need a test case that tests >0 and another need a test case that makes this whole thing false or true. E.g. in test case used 0.2 (false) and 1.5 (true) don’t have a discount rate below 0 -> interesting to test but does not affect branch coverage If tax_rate < 0 or tax_rate > 1 -> E.g. in test case used 0.1, -0.1 and 1.5 Fixtures and Mocks Test methods often use same test data that requires o Initialisation at the start of the test method (uniittest uses setUp() before every test method) - runs setUp first before the other tests. o Initialisation at the end of the test method (uniittest uses tearDown() after every test method) Test fixtures: common test data E.g. of setUp() BEFORE AFTER Within the scope of the setUp method, common test objects (e.g. a1) need to be assigned to an attribute to call it in other tests. (instead of a1 = BankAccount(400, ‘Chester’) should be self.a1 = BankAccount(400, ‘ Chester’)). Then to run tests, in the test method need to also use self.a1 to call it In reality we don't really need tearDown() as every time you run a new test, we are defining the objects. This is just to illustrate. More useful if dealing with databases. Because at the end of the testing session, we want to remove the connection with db. Mock framework Use Case 1: when u hv nondeterministic things - i.e. things u cant control / keep changing and u can't predict like random numbers, date time objects - then u mock the data to make the test repeatable o Mock a return value for the non deterministic entities. Use Case 2: want to test a function that relies on function and methods that are not yet implemented e.g code checks if person is underaged based on current date so need to mock data cus current date changes all the time Code Test with Magic Mock Mocks in Unit Testing Useful in unit testing when it is impossible or impractical to incorporate a real object into the test o E.g. objects that are yet to be implemented, have non-derterministic results, interface with external infrastructure such as db, brokrs Overuse of mocks in a test suite can however, dramatically increase maintenance required on tests themselves (for those that mock data for codes that have yet to be implemented, they should be replaced eventually otherwise will result in divergence on what you are testing and what system actually does) o E.g. Bugs may be missed if the real class is refactored at some point but mocked objects are not. Integration Test Unit tests helps find bugs in individual classes and functions Integration testing : testing whether parts of your system integrate o E.g. Do shopping cart and inventory management modules of an online shopping app work together seamlessly? Integration tests often involve db and other infrastructure.