Open Source Development, Intro
References for this Lesson
Brasseur, V. M. Forge Your Future with Open Source 1st ed., Pragmatic Bookshelf, 2018
Beck, Kent. Test-driven Development by Example. Vaseem: Addison-Wesley, 2002
Intro to Course …
whoami
- Who are you?
- Curriculum, the mid as it is called
From the MID
Indicative Content
Tools for team software development: version control (using subversion, mercurial or git, for example); bug tracking; testing frameworks; group communication tools;
Legal issues: the range of Free and Open-Source licenses; example legal cases regarding open-source software;
Open-source development: documentation of code and software, standards, cross-platform development and packaging of software, writing multilingual software.
Teaching and Learning
Learning will be facilitated through a variety of methods, which may include lectures, seminars, lab, workshops, online activities and group work. Students are expected to engage in both class and online activities and discussions. This module also requires students to participate in additional guided reading and self-directed study to reinforce the learning gained from timetabled sessions. Formative assessment will be used to prepare students for summative assessment and give students an early indication of their progress towards the course intended learning outcomes.
- expectations
- mode
- the lessons
- the exercises
- submissions
- exercises, README
- literature and other materials
Recapping Git for Our Context
Writing software that you intend to share, must be under
a Version Control System, a VCS. In this context this means
git
. Why git
? Because it is the best.
Sharing with someone who is not local? You must use one of the repository hosting services. The most well known are https://codeberg.org, https://gitlab.com, and https://github.com
To get started with a new project we have, by trial and error, found a useful workflow:
- Decide on a name for your project, use the same naming rules that you would use for a variable name in your favorite programming language. Choose a durable name.
- Log in to your account on https://codeberg.org, https://gitlab.com, or https://github.com
- Create an empty, or almost empty non private repo with your chosen name.
- Navigate to your projects directory
- On the CLI do
1 2 3
git clone https://codeberg.org/arosano/Examplar0 # or git clone https://github.com/nmliba/Examplar1
- Start working
- Commit and test often
- Push when tests indicate you have something to share
For this we have created a couple of exemplary near empty projects.
Read on below. The repo being non private means that others
may clone your repo. The partners you choose for collaborating
on the project must do that. Others may clone it.
Your collaborators should probably be allowed the necessary
permissions to push
changes to the repo.
Choose a good name. Once the repo is in the open you should not change it. Have you not chosen wisely, you do not rename, but archive the repo ie make read-only, and then create a new repo with a better name based on a branch of the project. Then you must of course inform stakeholders of the change.
- Checkout this repo: Codeberg version, or
- this Github version
- Read the README
- Check the
.gitignore
- Check the LICENSE
The .gitignore
is a long file which covers most
eventualities.
It is probably way over what we need in our coursework
and exercises. We chose a python
version for the Codeberg
repo, and a node
version for the Github version.
Re the licensing, there is the mentioned file with the full license. Int individual code files we may do something like the following:
|
|
or
|
|
Intro to Testing
Testing, Background
Computer systems must be tested. Hardware, or as in our context, systems, software. This is about testing.
There are several test concept in system engineering, devlopment, but they all have in common that the test should ascertain that the software does what it is supposed to do. This begs the question: what is it supposed to do?
What is it supposed to do? You will find the answer to that in the specs. This means that there is a proces preceding writing code. The developer gets a system specification explaining in detail what the requirements are. There are usually also a number of use cases involved. Use cases are part of user scenarios.
User Scenarios aka Use Cases
Use cases are part of UML, Unified Modelling Language6
Use Cases 1
- Requirements in a system entails:
- A need of classes, specific classes.
- A need of functionality, methods of the classes of the system.
- Use cases define the interface to the system.
- Use cases also define the entities of the system. Who needs it?
Use Cases 2
- A use case may be high level, quite abstract.
- It might be very detailed.
- It might be a diagram with few words.
- It might be verbose.
- It describes the what of the system.
- The developer uses it to write the how in the form of code.
Use Cases 3
The high level use case:
Figure 19.1. High Abstraction
Use Cases 4
A use case could be verbose:
- Fido barks meaning “I wanna get out!”
- Todd or Gina hears Fido barking.
- Todd or Gina aktivate the remote control.
- The door opens, sesame, sesame …
- Fido exits.
- Fido does what must be done.
- The door closes automatically
- Fido barks to signal “I wanna come back inside!”
- Todd or Gina hears Fido bark (again.)
- One of them activates the remote control (again.)
- The door reopens (again.)
- Fido enters.
- The door closes automatically.
Use Cases 5
- Point no 1 was a start condition.
- Subsequently a series of steps illustrate the interface behavior.
- The interface is between an actor and the system.
- A use case ends with an end condition.
- The detailed use case may be very concrete begging detailed code. The end condition must be testable.
Use Cases 6
A payment system example:
Figure 19.2. Payments
Aspects of Testing
Let us look at some focal points of testing with reference to SitePoint
We generally distinguish between different levels of software testing:
- Unit testing
- testing specific lines of code, functions, etc. Integration testing
- tests integration between units
- System testing
- tests the entire system.
- Acceptance testing
- checks the compliance with business goals as expressed in specs.
Generally speaking the former two are done by the developers, while the latter two involve testers and users.
Test Strategy
Apart from the professional pride of the developer, if that still exists, there are some overall limits that should be considered for a strategy. They include:
- Risks
- What are the business consequences if a bug were to affect this component?
- Time
- How soon must you deliver? Do you have a deadline?
- Budget
- How much money are you willing to spend on testing?
Risk, time, and budget are factors not just in software development, but are general project management topics.
Unit Test Characteristics
The main characteristics of unit tests are
- Speed
- Unit tests are mostly executed automatically, which means they must be fast. Slow unit tests are more likely to be skipped by developers because they don’t provide instant feedback.
- Isolation
- Unit tests are standalone by definition. Each test tests one thing. They don’t depend on anything external like a file or a network resource, if they depend on any other function, they are by definition an integration test.
- Repeatable
- Unit tests are executed repeatedly. They are contained in a program that you run.
- Reliable
- Unit tests themselves are tested before use. They may fail only if there’s a bug in the system being tested. They must be independent of environment, or the order of execution.
- Naming
- Proper naming is as essential in tests as in software development generally. The name of a test should be clear and unambiguous.
The Howto of Testing
Overview
Computer systems must be tested. Hardware, or as in our context, systems, i.e. software. This section is about testing.
Wikipedia has the following about test-driven development. It cites for this and for being the father of TDD. The quote has been cleaned from Wikipedia internal links. The Wikipedia article is very well referenced. Use the link above.
- _1. Add a test
- The adding of a new feature begins by writing a test that passes if and only if the feature’s specifications are met. The developer can discover these specifications by asking about use cases and user stories. A key benefit of test-driven development is that it makes the developer focus on requirements before writing code. This is in contrast with the usual practice, where unit tests are only written after code.
- _2. Run all tests. The new test should fail for expected reasons
- This shows that new code is actually needed for the desired feature. It validates that the test harness is working correctly. It rules out the possibility that the new test is flawed and will always pass.
- _3. Write the simplest code that passes the new test
- Inelegant or hard code is acceptable, as long as it passes the test. The code will be honed anyway in Step 5. No code should be added beyond the tested functionality.
- _4. All tests should now pass
- If any fail, the new code must be revised until they pass. This ensures the new code meets the test requirements and does not break existing features.
- _5. Refactor as needed, using tests after each refactor
- to ensure that functionality is preserved
- Code is refactored for readability and maintainability. In particular, hard-coded test data should be removed. Running the test suite after each refactor helps ensure that no existing functionality is broken.
Examples of refactoring
- moving code to where it most logically belongs
- removing duplicate code
- making names self-documenting
- splitting methods into smaller pieces
- re-arranging inheritance hierarchies
- Repeat
- The cycle above is repeated for each new piece of functionality. Tests should be small and incremental, and commits made often. That way, if new code fails some tests, the programmer can simply undo or revert rather than debug excessively. When using external libraries, it is important not to write tests that are so small as to effectively test merely the library itself, unless there is some reason to believe that the library is buggy or not feature-rich enough to serve all the needs of the software under development.
Testing Pattern
SitePoint advocates what they call the AAA pattern.
The Arrange, Act and Assert pattern is a common strategy used to write and organize unit tests. It works in the following way:
- During the Arrange phase, all the objects and variables needed for the test are set.
- Next, during the Act phase, the function/method/class under test is called.
- In the end, during the Assert phase, we verify the outcome of the test.
This strategy provides a clean approach to organizing unit tests by separating all the main parts of a test: setup, execution and verification. Plus, unit tests are easier to read, because they all follow the same structure.
Now, let us proceed in more concrete direction.
Code
Now take your pick, choose one of the following
or
and return to here when you are done.
Exercises
The rules for submitting solutions may be found in the README
For the following three exercises create one project directory:
|
|
and make the repo for submission in exercises_DS0
.
You may solve them in
either JavaScript or Python. Your choice!
Exercise OSD.0.0
Given the following specification, first write at
least three tests into the file testsuite.py
for
the functions the program to fulfill the specification
need to contain. Then write the program. Remember
to test frequently. The tests help you.
Specification
Write a program that prints the numbers from 1 through 100 on the console with three exceptions:
- If 3 divides the number write “Fizz” instead of the number
- If 5 divides the number write “Buzz” instead of the number
- If both 3 and 5 divide the number write “fizzBuzz”
Sample output:
|
|
Exercise OSD.0.1
First a couple of definitions:
Definition 1:
Re Wikipedia:
A palindrome is a word, number, phrase, or other sequence of symbols that reads the same backwards as forwards, such as madam or racecar, the date “22/02/2022” and the sentence: “A man, a plan, a canal – Panama”.
Definition 2:
A palindrome is a string whose first and last characters are the same, and the strings between the first and the last characters are a palindrome.
The first definition implies that spaces and punctuation is ignored.
Given the following specification, first write at
least three tests into the file testsuite.py
for
the functions the program to fulfill the specification
need to contain. Then write the program. Remember
to test frequently. The tests help you.
Specification
Write a function that takes a string as input, and returns “true” if the string is a palindrome, and “false” if it is not.
Write a program that includes the codefile with the function, and tests words or phrases for “palindromy.”
Exercise OSD.0.2
A definition:
Re Wikipedia:
A prime number (or a prime) is a natural number greater than 1 that is not a product of two smaller natural numbers. A natural number greater than 1 that is not prime is called a composite number.
Given the following specification, first write at
least three tests into the file testsuite.py
for
the functions the program to fulfill the specification
need to contain. Then write the program. Remember
to test frequently. The tests help you.
Specification
Write a function that takes a natural number, a positive integer, as input, and returns “true” if the input is prime, and “false” if it is not.
Write a program that includes the codefile with the function, and tests the input for primality.
Test the function with, among others, the integers 9007199254740991, and 9007195909437503.