Packages and Modules
Unlock the power of reusable code and streamline your development process with Python's packages and modules.
In this chapter, we'll explore the fundamentals of Python packages and modules, which are essential for organizing and reusing code. You'll learn how to create, import, and manage modules and packages, as well as understand the difference between them. We'll also cover best practices for structuring your projects and using virtual environments to keep dependencies isolated. By the end of this chapter, you'll be equipped to write clean, modular, and maintainable code.
Creating and Using Packages
What is a Python Package?
A Python package is a way of structuring Python’s module namespace by using "dotted module names." Essentially, a package is a directory that contains a special file called __init__.py
and other Python modules or sub-packages. This file can be empty, but its presence indicates that the directory should be treated as a package.
How to Create a Python Package
Creating a Python package involves a few straightforward steps:
-
Create a Directory Structure: Start by creating a directory for your package. Inside this directory, create an
__init__.py
file. This file can be empty, but it is necessary for Python to recognize the directory as a package.mypackage/ __init__.py module1.py module2.py
-
Add Modules: Add your Python modules (
.py
files) to the package directory. Each module can contain functions, classes, and variables that you want to reuse across your project. -
Organize Sub-packages: If your package grows, you can create sub-packages by adding more directories with their own
__init__.py
files.mypackage/ __init__.py module1.py module2.py subpackage/ __init__.py submodule1.py
Importing Packages
To use a package, you need to import it. Python provides several ways to import packages and modules:
-
Basic Import: Import the entire package.
import mypackage
-
Import Specific Modules: Import specific modules from the package.
from mypackage import module1
-
Import Functions or Classes: Import specific functions or classes from a module within the package.
from mypackage.module1 import my_function
-
Import with Aliases: Use aliases to avoid naming conflicts or to simplify long names.
import mypackage as mp from mypackage.module1 import my_function as mf
Best Practices for Package Structure
Following best practices ensures that your packages are easy to maintain and use:
- Consistent Naming: Use lowercase names for packages and modules to follow Python’s naming conventions.
- Documentation: Include docstrings in your modules and packages to explain their purpose and usage.
- Version Control: Use version control systems like Git to manage changes to your packages.
- Testing: Write unit tests for your modules to ensure they work as expected.
Using Virtual Environments
Virtual environments are crucial for managing dependencies and isolating your project’s environment. Here’s how to use them:
-
Create a Virtual Environment: Use the
venv
module to create a virtual environment.python -m venv myenv
-
Activate the Virtual Environment:
-
On Windows:
myenv\Scripts\activate
-
On macOS and Linux:
source myenv/bin/activate
-
-
Install Dependencies: Use
pip
to install the necessary packages within the virtual environment.pip install requests
-
Deactivate the Virtual Environment: When you’re done, deactivate the virtual environment to return to the global Python environment.
deactivate
Managing Dependencies
To manage dependencies effectively:
-
Requirements File: Create a
requirements.txt
file to list all the dependencies for your project.requests==2.25.1 numpy==1.19.5
-
Install from Requirements File: Use
pip
to install all dependencies listed in therequirements.txt
file.pip install -r requirements.txt
Example: Creating a Simple Package
Let’s create a simple package called math_utils
with two modules: arithmetic.py
and geometry.py
.
-
Directory Structure:
math_utils/ __init__.py arithmetic.py geometry.py
-
arithmetic.py:
def add(a, b): return a + b def subtract(a, b): return a - b
-
geometry.py:
def circle_area(radius): return 3.14159 * radius * radius def rectangle_area(length, width): return length * width
-
Using the Package:
from math_utils.arithmetic import add, subtract from math_utils.geometry import circle_area, rectangle_area print(add(5, 3)) # Output: 8 print(subtract(10, 4)) # Output: 6 print(circle_area(5)) # Output: 78.53975 print(rectangle_area(4, 6)) # Output: 24
By following these steps and best practices, you can create well-organized, maintainable, and reusable Python packages. This will not only improve your code quality but also make it easier for others to understand and contribute to your projects.## Modules in GoLang
Understanding Go Modules
Go modules are the standard way to manage dependencies in Go (Golang) projects. Introduced in Go 1.11 and made the default in Go 1.13, modules provide a simple and efficient way to handle versioning and dependency management. A Go module is defined by a go.mod
file, which specifies the module's path and its dependencies.
Creating a Go Module
To create a Go module, follow these steps:
-
Initialize the Module: Navigate to your project directory and run the following command to initialize a new module. Replace
example.com/yourmodule
with your module's path.go mod init example.com/yourmodule
This command creates a
go.mod
file in your project directory. -
Add Dependencies: Use the
go get
command to add dependencies to your module. For example, to add thegithub.com/sirupsen/logrus
package, run:go get github.com/sirupsen/logrus
This command updates the
go.mod
file with the new dependency and downloads the necessary packages.
The go.mod
File
The go.mod
file is the heart of a Go module. It contains the module's path, Go version, and a list of required dependencies. Here's an example of what a go.mod
file might look like:
module example.com/yourmodule
go 1.18
require (
github.com/sirupsen/logrus v1.8.1
github.com/spf13/cobra v1.1.3
)
- module: Specifies the module's path.
- go: Specifies the Go version required for the module.
- require: Lists the module's dependencies and their versions.
Managing Dependencies
Effective dependency management is crucial for maintaining a healthy Go project. Here are some best practices:
- Use Semantic Versioning: Follow semantic versioning (semver) to manage dependency versions. This helps in understanding the impact of version changes.
- Regularly Update Dependencies: Keep your dependencies up-to-date to benefit from the latest features and security patches. Use tools like
go list -u -m all
to list outdated dependencies. - Vendor Dependencies: Use the
go mod vendor
command to create avendor
directory containing all dependencies. This ensures that your project is self-contained and can be built without accessing external networks.
Using Go Modules in Your Project
To use Go modules in your project, follow these steps:
-
Import Packages: Import the required packages in your Go files. For example:
import ( "github.com/sirupsen/logrus" "github.com/spf13/cobra" )
-
Build and Run: Use the
go build
andgo run
commands to build and run your project. Go will automatically use the dependencies specified in thego.mod
file.go build go run main.go
Best Practices for Go Modules
Following best practices ensures that your Go modules are robust and maintainable:
- Consistent Module Paths: Use consistent and meaningful module paths. Avoid using local paths or paths that include version numbers.
- Documentation: Include clear documentation in your
go.mod
file and module code to explain the purpose and usage of your module. - Testing: Write comprehensive tests for your module to ensure its functionality and reliability.
- Security: Regularly check for security vulnerabilities in your dependencies using tools like
go list -f '{{.Path}} @ {{.Version}}' -m all
andgo get -u
to update dependencies.
Example: Creating a Simple Go Module
Let's create a simple Go module called greetings
that provides a function to generate greetings.
-
Directory Structure:
greetings/ go.mod greetings.go
-
Initialize the Module:
go mod init example.com/greetings
-
greetings.go:
package greetings import "fmt" // Hello returns a greeting message. func Hello(name string) string { return fmt.Sprintf("Hello, %s!", name) }
-
Using the Module:
Create another module that uses the
greetings
module.main/ go.mod main.go
go mod init example.com/main go get example.com/greetings
package main import ( "fmt" "example.com/greetings" ) func main() { message := greetings.Hello("World") fmt.Println(message) }
By following these steps and best practices, you can create well-organized, maintainable, and reusable Go modules. This will not only improve your code quality but also make it easier for others to understand and contribute to your projects.## Dependency Management
Effective dependency management is crucial for maintaining robust and scalable software projects. Whether you're working with Python or GoLang, understanding how to manage dependencies ensures that your projects remain secure, up-to-date, and easy to maintain. This section delves into the best practices and tools for dependency management in both Python and GoLang.
Dependency Management in Python
Python offers several tools and best practices for managing dependencies, ensuring that your projects remain stable and secure.
Using requirements.txt
The requirements.txt
file is a standard way to list the dependencies for a Python project. This file specifies the packages and their versions required for your project to run.
Creating a requirements.txt
File:
-
Generate Requirements: Use the
pip freeze
command to generate arequirements.txt
file that lists all installed packages and their versions.pip freeze > requirements.txt
-
Install from
requirements.txt
: Use thepip install -r requirements.txt
command to install all dependencies listed in the file.pip install -r requirements.txt
Example requirements.txt
:
requests==2.25.1
numpy==1.19.5
pandas==1.1.5
Using pipenv
pipenv
is a tool that aims to bring the best of all packaging worlds (bundled, unbundled, and virtualized) to the Python world. It automatically creates and manages a virtual environment for your projects, as well as a Pipfile
to manage dependencies.
Installing pipenv
:
pip install pipenv
Creating a Pipfile
:
-
Initialize Pipenv: Navigate to your project directory and run
pipenv install
to create aPipfile
.pipenv install
-
Add Dependencies: Use
pipenv install <package>
to add dependencies to yourPipfile
.pipenv install requests
-
Install Dependencies: Use
pipenv install
to install all dependencies listed in thePipfile
.pipenv install
Example Pipfile
:
[[source]]
name = "pypi"
url = "https://pypi.org/simple"
verify_ssl = true
[packages]
requests = "==2.25.1"
numpy = "==1.19.5"
pandas = "==1.1.5"
Using poetry
poetry
is another dependency management tool that focuses on simplicity and consistency. It uses a pyproject.toml
file to manage dependencies and project metadata.
Installing poetry
:
curl -sSL https://install.python-poetry.org | python3 -
Creating a pyproject.toml
File:
-
Initialize Poetry: Navigate to your project directory and run
poetry init
to create apyproject.toml
file.poetry init
-
Add Dependencies: Use
poetry add <package>
to add dependencies to yourpyproject.toml
file.poetry add requests
-
Install Dependencies: Use
poetry install
to install all dependencies listed in thepyproject.toml
file.poetry install
Example pyproject.toml
:
[tool.poetry]
name = "myproject"
version = "0.1.0"
description = ""
authors = ["Your Name <you@example.com>"]
[tool.poetry.dependencies]
python = "^3.8"
requests = "^2.25.1"
numpy = "^1.19.5"
pandas = "^1.1.5"
Dependency Management in GoLang
GoLang provides a robust system for managing dependencies through Go modules. Understanding how to use Go modules effectively is essential for maintaining clean and efficient Go projects.
Using go.mod
The go.mod
file is the cornerstone of Go modules. It specifies the module's path, Go version, and required dependencies.
Creating a go.mod
File:
-
Initialize the Module: Navigate to your project directory and run
go mod init
to create ago.mod
file.go mod init example.com/yourmodule
-
Add Dependencies: Use
go get
to add dependencies to yourgo.mod
file.go get github.com/sirupsen/logrus
Example go.mod
:
module example.com/yourmodule
go 1.18
require (
github.com/sirupsen/logrus v1.8.1
github.com/spf13/cobra v1.1.3
)
Managing Dependencies
Effective dependency management in GoLang involves several best practices:
- Use Semantic Versioning: Follow semantic versioning (semver) to manage dependency versions. This helps in understanding the impact of version changes.
- Regularly Update Dependencies: Keep your dependencies up-to-date to benefit from the latest features and security patches. Use tools like
go list -u -m all
to list outdated dependencies. - Vendor Dependencies: Use the
go mod vendor
command to create avendor
directory containing all dependencies. This ensures that your project is self-contained and can be built without accessing external networks.
Updating Dependencies:
go get -u
Vendoring Dependencies:
go mod vendor
Using go.sum
The go.sum
file is automatically generated by Go and contains checksums for the dependencies specified in the go.mod
file. This file ensures the integrity and security of your dependencies.
Example go.sum
:
github.com/sirupsen/logrus v1.8.1/go.mod h1:...
github.com/spf13/cobra v1.1.3/go.mod h1:...
Best Practices for Dependency Management
Regardless of the language, following best practices for dependency management is essential for maintaining healthy and secure projects.
- Consistent Versioning: Use consistent versioning strategies to avoid conflicts and ensure compatibility.
- Regular Audits: Regularly audit your dependencies to identify and address security vulnerabilities.
- Documentation: Maintain clear documentation for your dependencies, including their purpose and usage.
- Automated Testing: Implement automated testing to ensure that your dependencies work as expected and do not introduce regressions.
By adhering to these best practices and utilizing the right tools, you can effectively manage dependencies in your Python and GoLang projects, ensuring they remain secure, up-to-date, and easy to maintain.## Documenting Your Code
Why Document Your Code?
Documenting your code is a critical practice that enhances code readability, maintainability, and collaboration. Well-documented code serves as a roadmap for developers, making it easier to understand the purpose, functionality, and usage of modules and packages. This is particularly important in large projects where multiple developers may contribute to the codebase.
Types of Code Documentation
Effective code documentation includes several types, each serving a specific purpose:
- Inline Comments: Brief explanations within the code to clarify complex logic or non-obvious decisions.
- Docstrings: Detailed descriptions of modules, classes, and functions, typically placed at the beginning of the code block.
- README Files: Comprehensive overviews of the project, including installation instructions, usage examples, and contribution guidelines.
- API Documentation: Detailed descriptions of the public interfaces, including parameters, return values, and usage examples.
Best Practices for Inline Comments
Inline comments should be concise and focused on explaining why the code does something, rather than what it does. Here are some best practices:
- Be Concise: Keep comments short and to the point.
- Explain the Why: Focus on the rationale behind the code, not the mechanics.
- Avoid Obvious Comments: Don't comment on obvious code; focus on complex or non-intuitive parts.
- Use Consistent Style: Follow a consistent commenting style throughout the codebase.
Example:
# Calculate the discount based on the customer's loyalty points
discount = loyalty_points * 0.05
Writing Effective Docstrings
Docstrings are essential for documenting modules, classes, and functions. They provide a clear and concise explanation of what the code does, its parameters, return values, and any exceptions it may raise.
Structure of a Docstring:
- Summary Line: A brief description of the function or class.
- Blank Line: Separates the summary from the detailed description.
- Detailed Description: Explains the purpose, parameters, return values, and any exceptions.
- Examples: Provides usage examples to illustrate how the function or class is used.
Example:
def calculate_discount(price, loyalty_points):
"""
Calculate the discount based on the customer's loyalty points.
Args:
price (float): The original price of the item.
loyalty_points (int): The number of loyalty points the customer has.
Returns:
float: The discounted price.
Raises:
ValueError: If loyalty_points is negative.
"""
if loyalty_points < 0:
raise ValueError("Loyalty points cannot be negative.")
discount = loyalty_points * 0.05
return price - discount
Creating Comprehensive README Files
A well-written README file is the first point of contact for anyone interacting with your project. It should provide a clear overview of the project, including its purpose, installation instructions, usage examples, and contribution guidelines.
Structure of a README File:
- Project Title and Description: A brief description of the project.
- Table of Contents: A list of sections for easy navigation.
- Installation Instructions: Step-by-step instructions for installing the project.
- Usage Examples: Examples of how to use the project.
- Contribution Guidelines: Instructions for contributing to the project.
- License: Information about the project's license.
Example:
# Project Title
A brief description of the project.
## Table of Contents
- [Installation](#installation)
- [Usage](#usage)
- [Contributing](#contributing)
- [License](#license)
## Installation
1. Clone the repository:
```bash
git clone https://github.com/yourusername/yourproject.git
- Navigate to the project directory:
cd yourproject
- Install the dependencies:
pip install -r requirements.txt
Usage
Example of how to use the project:
from yourmodule import your_function
result = your_function(10, 20)
print(result)
Contributing
Contributions are welcome! Please follow these steps:
- Fork the repository.
- Create a new branch:
git checkout -b feature-branch
- Make your changes and commit them:
git commit -m "Add new feature"
- Push to the branch:
git push origin feature-branch
- Create a pull request.
License
This project is licensed under the MIT License.
### Generating API Documentation
API documentation provides detailed information about the public interfaces of your code. Tools like Sphinx (for Python) and godoc (for GoLang) can automatically generate API documentation from docstrings and comments.
**Using Sphinx for Python:**
1. **Install Sphinx**:
```bash
pip install sphinx
-
Initialize Sphinx:
sphinx-quickstart
-
Configure Sphinx: Edit the
conf.py
file to include your project's modules. -
Generate Documentation:
make html
-
View Documentation: Open the
index.html
file in your browser to view the generated documentation.
Using godoc for GoLang:
-
Install godoc:
go get golang.org/x/tools/cmd/godoc
-
Generate Documentation:
godoc -http=:6060
-
View Documentation: Open your browser and navigate to
http://localhost:6060/pkg/yourmodule/
to view the generated documentation.
Tools for Code Documentation
Several tools can help streamline the documentation process:
- Sphinx: A powerful documentation generator for Python projects.
- godoc: A documentation generator for GoLang projects.
- Doxygen: A versatile documentation generator that supports multiple programming languages.
- JSDoc: A documentation generator for JavaScript projects.
Integrating Documentation into Your Workflow
Integrating documentation into your development workflow ensures that it remains up-to-date and relevant. Here are some tips:
- Document as You Code: Write comments and docstrings as you develop your code.
- Review Documentation: Include documentation reviews in your code review process.
- Automate Documentation Generation: Use tools to automatically generate documentation from comments and docstrings.
- Keep Documentation Updated: Regularly update documentation to reflect changes in the codebase.
Example: Documenting a Python Package
Let's document a simple Python package called math_utils
with two modules: arithmetic.py
and geometry.py
.
-
Directory Structure:
math_utils/ __init__.py arithmetic.py geometry.py README.md
-
arithmetic.py:
def add(a, b): """ Add two numbers. Args: a (float): The first number. b (float): The second number. Returns: float: The sum of the two numbers. """ return a + b def subtract(a, b): """ Subtract the second number from the first. Args: a (float): The first number. b (float): The second number. Returns: float: The difference between the two numbers. """ return a - b
-
geometry.py:
def circle_area(radius): """ Calculate the area of a circle. Args: radius (float): The radius of the circle. Returns: float: The area of the circle. """ return 3.14159 * radius * radius def rectangle_area(length, width): """ Calculate the area of a rectangle. Args: length (float): The length of the rectangle. width (float): The width of the rectangle. Returns: float: The area of the rectangle. """ return length * width
-
README.md:
# Math Utils A collection of utility functions for mathematical operations. ## Table of Contents - [Installation](#installation) - [Usage](#usage) - [Modules](#modules) ## Installation 1. Clone the repository: ```bash git clone https://github.com/yourusername/math_utils.git
- Navigate to the project directory:
cd math_utils
- Install the dependencies:
pip install -r requirements.txt
Usage
Example of how to use the
math_utils
package:from math_utils.arithmetic import add, subtract from math_utils.geometry import circle_area, rectangle_area print(add(5, 3)) # Output: 8 print(subtract(10, 4)) # Output: 6 print(circle_area(5)) # Output: 78.53975 print(rectangle_area(4, 6)) # Output: 24
Modules
arithmetic.py
: Functions for basic arithmetic operations.geometry.py
: Functions for geometric calculations.
- Navigate to the project directory:
By following these best practices and utilizing the right tools, you can create comprehensive and effective documentation for your code. This will not only improve the maintainability and readability of your codebase but also make it easier for others to understand and contribute to your projects.## Testing Your Code
Importance of Code Testing
Testing your code is a critical step in the software development process. It ensures that your modules and packages function as expected, are reliable, and can handle various edge cases. Effective testing helps catch bugs early, improves code quality, and makes your codebase more maintainable. By integrating testing into your development workflow, you can build robust and scalable applications.
Types of Testing
Understanding the different types of testing is essential for creating a comprehensive testing strategy. Here are the primary types of testing you should consider:
- Unit Testing: Tests individual components or functions in isolation to ensure they work correctly.
- Integration Testing: Tests the interaction between different modules or services to ensure they work together as expected.
- System Testing: Tests the entire system to verify that it meets the specified requirements.
- Acceptance Testing: Tests the system from the end-user's perspective to ensure it meets their needs and expectations.
Writing Unit Tests in Python
Unit tests are the foundation of a robust testing strategy. In Python, the unittest
module provides a framework for writing and running unit tests. Here’s how to write unit tests for your Python modules:
Setting Up Unit Tests
-
Create a Test Directory: Organize your tests in a separate directory, typically named
tests
.mypackage/ __init__.py module1.py module2.py tests/ __init__.py test_module1.py test_module2.py
-
Write Test Cases: Use the
unittest
framework to write test cases for your modules.# tests/test_module1.py import unittest from mypackage.module1 import add, subtract class TestModule1(unittest.TestCase): def test_add(self): self.assertEqual(add(5, 3), 8) self.assertEqual(add(-1, 1), 0) self.assertEqual(add(-1, -1), -2) def test_subtract(self): self.assertEqual(subtract(10, 4), 6) self.assertEqual(subtract(-1, 1), -2) self.assertEqual(subtract(-1, -1), 0) if __name__ == '__main__': unittest.main()
-
Run Tests: Use the
unittest
command to run your tests.python -m unittest discover -s tests
Using pytest
pytest
is a popular testing framework that provides a more flexible and powerful alternative to unittest
. Here’s how to use pytest
for testing your Python modules:
-
Install
pytest
:pip install pytest
-
Write Test Cases: Use
pytest
to write test cases for your modules.# tests/test_module1.py from mypackage.module1 import add, subtract def test_add(): assert add(5, 3) == 8 assert add(-1, 1) == 0 assert add(-1, -1) == -2 def test_subtract(): assert subtract(10, 4) == 6 assert subtract(-1, 1) == -2 assert subtract(-1, -1) == 0
-
Run Tests: Use the
pytest
command to run your tests.pytest
Writing Unit Tests in GoLang
In GoLang, the testing
package provides a built-in framework for writing and running unit tests. Here’s how to write unit tests for your Go modules:
Setting Up Unit Tests
-
Create a Test File: Create a test file with the
_test.go
suffix in the same directory as your module.greetings/ greetings.go greetings_test.go
-
Write Test Cases: Use the
testing
package to write test cases for your module.// greetings_test.go package greetings import "testing" func TestHello(t *testing.T) { got := Hello("World") want := "Hello, World!" if got != want { t.Errorf("Hello(\"World\") = %q, want %q", got, want) } }
-
Run Tests: Use the
go test
command to run your tests.go test
Using Table-Driven Tests
Table-driven tests are a powerful technique for writing concise and maintainable tests in Go. Here’s an example of a table-driven test:
// greetings_test.go
package greetings
import "testing"
func TestHello(t *testing.T) {
tests := []struct {
input string
expected string
}{
{"World", "Hello, World!"},
{"Go", "Hello, Go!"},
{"", "Hello, !"},
}
for _, tt := range tests {
got := Hello(tt.input)
if got != tt.expected {
t.Errorf("Hello(%q) = %q, want %q", tt.input, got, tt.expected)
}
}
}
Best Practices for Code Testing
Following best practices ensures that your tests are effective and maintainable:
- Write Tests Early: Integrate testing into your development process from the beginning. Write tests before or alongside your code to catch issues early.
- Test Small Units: Focus on testing small, isolated units of code. This makes it easier to identify and fix issues.
- Use Descriptive Names: Use descriptive names for your test cases and functions to make it clear what is being tested.
- Automate Testing: Use continuous integration (CI) tools to automate the testing process. This ensures that tests are run consistently and regularly.
- Cover Edge Cases: Test edge cases and unexpected inputs to ensure your code handles them gracefully.
- Keep Tests Independent: Ensure that tests are independent of each other. This makes it easier to run tests in parallel and isolate issues.
Tools for Code Testing
Several tools can help streamline the testing process:
unittest
andpytest
: Popular testing frameworks for Python.testing
Package: Built-in testing framework for GoLang.mockito
: A mocking framework for Python that helps in testing code with dependencies.testify
: A testing framework for GoLang that provides additional assertions and mocking capabilities.JUnit
: A popular testing framework for Java.Mocha
andJest
: Popular testing frameworks for JavaScript.
Integrating Testing into Your Workflow
Integrating testing into your development workflow ensures that it remains a priority and is consistently applied. Here are some tips:
- Test-Driven Development (TDD): Adopt TDD to write tests before writing code. This helps in designing code that is testable and reliable.
- Code Reviews: Include testing in your code review process. Ensure that tests are written for new features and that existing tests are updated as needed.
- Continuous Integration (CI): Use CI tools to automate the testing process. This ensures that tests are run consistently and regularly.
- Regular Testing: Make testing a regular part of your development process. Run tests frequently to catch issues early.
Example: Testing a Python Package
Let's test the math_utils
package with two modules: arithmetic.py
and geometry.py
.
-
Directory Structure:
math_utils/ __init__.py arithmetic.py geometry.py tests/ __init__.py test_arithmetic.py test_geometry.py
-
test_arithmetic.py:
import unittest from math_utils.arithmetic import add, subtract class TestArithmetic(unittest.TestCase): def test_add(self): self.assertEqual(add(5, 3), 8) self.assertEqual(add(-1, 1), 0) self.assertEqual(add(-1, -1), -2) def test_subtract(self): self.assertEqual(subtract(10, 4), 6) self.assertEqual(subtract(-1, 1), -2) self.assertEqual(subtract(-1, -1), 0) if __name__ == '__main__': unittest.main()
-
test_geometry.py:
import unittest from math_utils.geometry import circle_area, rectangle_area class TestGeometry(unittest.TestCase): def test_circle_area(self): self.assertAlmostEqual(circle_area(5), 78.53975) self.assertAlmostEqual(circle_area(0), 0) self.assertAlmostEqual(circle_area(-5), 78.53975) # Edge case def test_rectangle_area(self): self.assertEqual(rectangle_area(4, 6), 24) self.assertEqual(rectangle_area(0, 6), 0) self.assertEqual(rectangle_area(-4, 6), 0) # Edge case if __name__ == '__main__': unittest.main()
-
Run Tests:
python -m unittest discover -s tests
By following these best practices and utilizing the right tools, you can create comprehensive and effective tests for your code. This will not only improve the reliability and maintainability of your codebase but also make it easier for others to understand and contribute to your projects.