CalculatorApplicationWithUnittesting-2 (2)
CalculatorApplicationWithUnittesting-2 (2)
TESTING
By
Bitra Bhavani
23BQ1A4220
CERTIFICATE
This is to certify that the project titled “Calculator Application With Unit
Testing” is a bonafide record of work done by Ms. Bitra Bhavani under the guidance
of Mr. M. Pardha Saradhi, Associate Professor in partial fulfillment of the
requirement for the award of credits to Python - a skill enhancement course of
Bachelor of Technology in Computer Science & Engineering – Artificial Intelligence &
Machine Learning (CSM), JNTUK during the academic year 2024-25.
I, BITRA BHAVANI (23BQ1A4220), hereby declare that the Project Report entitled
“CALCULATOR APPLICATION WITH UNIT TESTING” done by me under the
guidance of Mr. M. Pardha Saradhi, Associate Professor is submitted in partial
fulfillment of the requirements for the award of degree of BACHELOR OF
TECHNOLOGY in COMPUTER SCIENCE & ENGINEERING – ARTIFICIAL
INTELLIGENCE & MACHINE LEARNING (CSM).
PLACE :
Bitra Bhavani
ACKNOWLEDGEMENT
We also place our floral gratitude to all other teaching staff and
lab technicians for their constant support and advice throughout the
project.
Bitra Bhavani
23BQ1A4220
Abstract
This project focuses on the development and testing of a scientific calculator application using
Python, with an emphasis on unit testing to ensure the accuracy and reliability of its
operations. The calculator is designed with a comprehensive set of mathematical functions,
including basic arithmetic (addition, subtraction, multiplication, and division), advanced
operations such as square roots, powers, logarithms, and trigonometric functions (sine,
cosine, tangent), as well as special functions like factorials and percentages. These operations
are implemented in the Calculator class, which serves as the core computational engine.
The project integrates a graphical user interface (GUI) built with Python's Tkinter library,
offering an intuitive, user-friendly design. The GUI allows users to interact with the calculator
through buttons for each operation, an entry field for displaying input/output, and error
handling for invalid operations such as division by zero, taking square roots of negative
numbers, and attempting to compute the logarithm of non-positive values.
To ensure the calculator performs accurately across all operations, unit testing is employed
using Python’s unittest framework. The testing suite validates each mathematical function,
ensuring that the calculator provides the correct results for both typical cases and edge cases,
such as division by zero or factorial calculations for negative numbers. Additionally, error
handling is rigorously tested to confirm that appropriate exceptions are raised in response to
invalid inputs. These tests are designed to ensure the robustness and precision of the
calculator.
The application also utilizes multithreading to run the Tkinter-based GUI in a separate thread,
preventing the interface from freezing during calculations. The project, therefore, not only
offers a fully functional scientific calculator but also demonstrates the importance of unit
testing in software development to guarantee both performance and reliability. This
combination of GUI development, mathematical computation, and testing ensures the tool’s
effectiveness for both casual users and those requiring advanced mathematical functions.
Chapter 1: Introduction to Calculator application
with unit testing
Objectives:
The primary objectives of this project are:
1. Test Calculator Accuracy and Reliability: Verify that each mathematical operation works
correctly and produces accurate results.
2. Automate Error Handling: Ensure the calculator handles edge cases (e.g., invalid inputs)
gracefully, such as raising appropriate errors for division by zero.
3. Create a Robust Test Suite: Implement automated tests using the unittest framework to
ensure that each function (addition, subtraction, etc.) is correctly implemented and behaves
as expected.
4. Enhance Software Quality: By using automated testing, ensure the calculator maintains
high reliability and can be safely modified or extended in the future without introducing bugs.
Project Workflow:
The project follows a structured workflow focused on testing the Calculator Application:
1. Design Test Cases: Identify and create test cases for each calculator function (addition,
subtraction, trigonometric functions, etc.), including typical and edge cases (e.g., handling
division by zero).
2. Write Unit Tests: Implement unit tests using unittest to check each function's correctness
and ensure that invalid inputs are handled appropriately.
3. Run and Debug Tests: Execute the unit tests and fix any issues revealed by failed tests. This
step ensures that each mathematical operation and error condition is correctly handled.
4. Regression Testing: After changes or updates to the application, run the tests again to
ensure new code does not introduce new issues.
5. Continuous Integration: If applicable, integrate the tests into a CI pipeline for automated
testing after every code change.
Applications:
The testing of the Calculator Application has several practical applications:
1. Software Quality Assurance: This project highlights how unit testing ensures that each
function of a software application is reliable and works correctly.
2. Automated Regression Testing: The unit tests allow for automated regression testing,
ensuring that future updates or modifications do not break existing functionality.
3. Educational Tool: The project serves as a learning resource for those interested in unit
testing, showing how to write tests for mathematical functions and handle common errors.
4. Enhancement Foundation: The test suite can be extended as new features are added to the
calculator (e.g., advanced graphing capabilities, additional scientific functions).
This project’s main focus is to test the Calculator Application to ensure that all of its
mathematical functions work as intended and handle edge cases appropriately. By utilizing
the unittest framework, the tests automate the validation process, making it easier to ensure
software reliability and robustness.
The use of automated tests improves the quality of the software and facilitates easier
maintenance, allowing future developers to confidently make changes without fear of
introducing new bugs. This project demonstrates the significance of unit testing in software
development, especially for applications that require high accuracy and robust error handling,
such as a calculator.
Chapter 2: Introduction to Libraries and Tools Used for
Calculator application with unit testing
In the development of any software application, choosing the right libraries and tools is crucial
to ensuring its functionality, efficiency, and scalability. For the Calculator Application, a
carefully selected set of libraries and tools was leveraged to create a user-friendly, responsive,
and high-performance solution. This chapter introduces and explores the various libraries and
tools employed during the development process.
We begin with the Python programming language, which serves as the foundation of the
application, providing a simple yet powerful environment for writing the code. From there,
we move on to specific libraries like Tkinter, which powers the graphical user interface (GUI),
enabling the creation of a clean, intuitive layout. For handling more advanced mathematical
functions and operations, we incorporated the math library, which extends the application’s
capabilities far beyond basic arithmetic.
Additionally, we discuss how the use of threading ensures that the application remains
responsive even when performing computationally intensive tasks. Regular expressions (re)
are also utilized for input validation, helping to process user inputs in an efficient and error-
free manner. Finally, we highlight the importance of unit testing with Python's built-in unittest
library, which was used to rigorously test the individual components of the application to
ensure that everything works as expected.
By examining the purpose, functionality, and integration of each of these tools, this chapter
will provide a comprehensive understanding of how they collectively contributed to the
development of the Calculator Application. Each tool has been carefully chosen to address
specific needs and enhance the overall user experience, creating a robust and reliable final
product.
These functions serve as the building blocks for the Calculator Application. The functions are
straightforward and handle basic arithmetic operations, a necessity for any calculator.
class CalculatorApp:
def __init__(self, root):
self.root = root
self.root.title("Simple Calculator")
self.input_var = tk.StringVar()
self.entry = tk.Entry(root, textvariable=self.input_var,
font=("Arial", 20), bd=5, relief="sunken", justify="right")
self.entry.grid(row=0, column=0, columnspan=4, padx=5, pady=5)
self.create_buttons()
def create_buttons(self):
button_texts = [
('7', 1, 0), ('8', 1, 1), ('9', 1, 2),
('4', 2, 0), ('5', 2, 1), ('6', 2, 2),
('1', 3, 0), ('2', 3, 1), ('3', 3, 2),
('0', 4, 1), ('+', 1, 3), ('-', 2, 3),
('*', 3, 3), ('/', 4, 3), ('=', 4, 2)
]
In this example, the CalculatorApp class initializes a Tkinter window with a basic layout for a
calculator, using Entry for the display area and Button widgets for each digit and operation.
3. Math (Mathematical Functions)
The math module in Python is a standard library that provides a variety of mathematical
functions, such as trigonometric functions, logarithms, and constants like pi and e.
def calculate_square_root(x):
if x < 0:
raise ValueError("Cannot calculate square root of a negative
number")
return math.sqrt(x)
These functions allow the calculator to handle more advanced operations like square roots
and powers, expanding its capabilities beyond basic arithmetic.
threading.Thread(target=calculate).start()
This code creates a new thread to calculate the factorial asynchronously. The Thread is launched
without blocking the main GUI thread, ensuring that the user interface remains responsive.
import re
def is_valid_expression(expression):
pattern = r'^[0-9+\-*/^(). ]+$'
return bool(re.match(pattern, expression))
def handle_factorial(expression):
match = re.search(r'(\d+)!', expression)
if match:
number = int(match.group(1))
return math.factorial(number)
return expression
In this example, regular expressions are used to validate input and identify factorial expressions in the
format 5!, which are then processed accordingly.
import unittest
class TestCalculator(unittest.TestCase):
def test_addition(self):
self.assertEqual(add(2, 3), 5)
def test_subtraction(self):
self.assertEqual(subtract(5, 3), 2)
def test_square_root(self):
self.assertEqual(calculate_square_root(4), 2)
if __name__ == '__main__':
unittest.main()
These tests check whether basic arithmetic functions work as expected, which helps ensure the
integrity of the application.
In this chapter, we have examined the key libraries and tools used in the development of the Calculator
Application, including Python, Tkinter, math, threading, re, and unittest. Each tool played a critical
role in the successful development of the application:
• The math module enhanced the calculator's functionality with advanced mathematical
operations.
• Threading ensured that long-running operations did not interfere with the user experience.
• Unit testing with unittest ensured that the application was thoroughly tested, minimizing bugs
and ensuring reliable performance.
Each of these tools was chosen carefully to enhance the overall user experience, functionality, and
maintainability of the Calculator Application.
In the next chapter, we will dive deeper into the design and implementation of the application's test
cases, focusing on how each part of the application was validated to ensure proper functionality under
various conditions.
Chapter 3: Design and Implementation of Unit Tests
for Calculator Application
Introduction
Unit testing is an essential practice in software development that helps ensure the accuracy
and functionality of an application. In this chapter, we’ll discuss the design and
implementation of unit tests for the Calculator Application built in Python. The tests will
cover both basic and advanced mathematical operations that the calculator performs,
including arithmetic operations (addition, subtraction, multiplication, division) and more
complex mathematical functions (square root, power, trigonometry, factorial, and
logarithms).
By writing unit tests, we can ensure that each component of the application behaves as
expected, handle edge cases properly, and deal with potential errors. The unittest framework
in Python is used to structure and run the tests.
Addition Test
The add() method in the calculator adds two numbers. The test case ensures that this
operation produces the expected result.
import unittest
from calculator import Calculator
class TestCalculator(unittest.TestCase):
def setUp(self):
self.calculator = Calculator()
def test_add(self):
self.assertEqual(self.calculator.add(2, 3), 5) #
Adding 2 and 3
self.assertEqual(self.calculator.add(-1, 1), 0) #
Adding -1 and 1
if __name__ == '__main__':
unittest.main()
Explanation:
• test_add: This test checks if the addition method works for both positive and negative
numbers. The first assertion checks that adding 2 and 3 results in 5. The second checks
that adding -1 and 1 results in 0.
Expected Output:
Subtraction Test
The subtract() method subtracts two numbers. The test case for subtraction ensures that the
operation works correctly, both when subtracting smaller numbers from larger ones and vice
versa.
def test_subtract(self):
self.assertEqual(self.calculator.subtract(5, 3), 2) # 5 - 3 = 2
self.assertEqual(self.calculator.subtract(3, 5), -2) # 3 - 5 = -
2
Explanation:
• test_subtract: The test checks two cases: subtracting 3 from 5, and subtracting 5 from
3. This verifies that the calculator correctly handles both positive and negative results.
Expected Output:
Multiplication Test
The multiply() method multiplies two numbers. Here’s the test for multiplication:
def test_multiply(self):
self.assertEqual(self.calculator.multiply(3, 4), 12) # 3 * 4 = 12
self.assertEqual(self.calculator.multiply(-3, 4), -12) # -3 * 4
= -12
Explanation:
• test_multiply: The test checks whether multiplication works for both positive and
negative numbers. It verifies that multiplying 3 and 4 results in 12 and that multiplying
-3 and 4 results in -12.
Expected Output:
Division Test
The divide() method performs division. A critical part of the test is checking for division by
zero, which should raise an exception.
def test_divide(self):
self.assertEqual(self.calculator.divide(10, 2), 5) # 10 / 2 = 5
with self.assertRaises(ValueError):
self.calculator.divide(10, 0) # Division by zero should raise
an error
Explanation:
• test_divide: The first assertion checks whether dividing 10 by 2 gives the correct result,
5. The second assertion checks if dividing by zero raises a ValueError, which is handled
by the calculator.
Expected Output:
Power Test
The power() method computes exponentiation (a raised to the power of b). We test it with
both positive and zero exponents.
def test_power(self):
self.assertEqual(self.calculator.power(2, 3), 8) # 2^3 = 8
self.assertEqual(self.calculator.power(5, 0), 1) # 5^0 = 1
Explanation:
• test_power: The first assertion checks that 2^3 equals 8. The second assertion tests
that any number raised to the power of 0 is 1.
Expected Output:
Factorial Test
The factorial() method calculates the factorial of a number. We test it for valid and invalid
inputs (e.g., negative numbers).
def test_factorial(self):
self.assertEqual(self.calculator.factorial(5), 120) # 5! = 120
with self.assertRaises(ValueError):
self.calculator.factorial(-1) # Factorial is not defined for
negative numbers
Explanation:
• test_factorial: The first assertion checks that the factorial of 5 is 120. The second
assertion ensures that attempting to calculate the factorial of a negative number raises
a ValueError.
Expected Output:
In this chapter, a comprehensive suite of unit tests for the Calculator Application was
implemented to ensure that the application performs its intended operations correctly and
handles various edge cases and errors gracefully. The tests covered a range of functionalities,
including:
• Basic arithmetic operations (addition, subtraction, multiplication, and division)
• Advanced mathematical functions such as square roots, powers, factorials, and
trigonometric calculations
• Error handling for invalid inputs and mathematically undefined operations (e.g.,
division by zero, logarithms of zero or negative numbers)
• Edge cases involving large and small numbers, ensuring the application can handle
extreme values.
Using Python's built-in unittest framework, each functionality was systematically verified in
isolation. This ensures that individual components work as expected, making the calculator
more reliable and robust.
Through these tests, it was confirmed that the application meets its design requirements and
provides a foundation for future development and maintenance. As the application evolves,
these unit tests will help detect regressions, allowing developers to confidently implement
new features without breaking existing functionality.
In summary, the implementation of unit tests is crucial in ensuring software reliability and
maintainability. It also fosters a development environment where bugs can be identified and
resolved early in the process, reducing long-term costs and improving the overall quality of
the application.
Chapter 4: Results and Discussion for the Calculator
Application with Unit Testing
Results
The Calculator Application with Unit Testing successfully performs various mathematical
operations and provides an intuitive user interface. The application is designed to handle basic
arithmetic, advanced mathematical functions, and display results efficiently. It also includes
automated unit testing to ensure the correctness of the operations. The results can be
categorized into the following areas:
1. Functionality:
o The calculator performs basic arithmetic operations such as addition,
subtraction, multiplication, and division accurately.
o Advanced mathematical functions like square root, power, percentage,
factorial, and trigonometric operations (sin, cos, tan) are implemented
correctly.
o Logarithmic functions and exponential calculations also return expected
results.
o The calculator displays appropriate error messages for invalid inputs, such as
division by zero or attempting the square root of a negative number.
Example of input and output:
o Addition: 2 + 3 = 5
o Division: 10 / 2 = 5
o Factorial: 5! = 120
o Sine: sin(pi/2) = 1
o Logarithm: log(10) = 1
3. Unit Testing:
o The unit tests cover all major operations, including basic arithmetic, advanced
functions, and error handling.
o The tests confirm that all operations return accurate results for various inputs.
o The error handling mechanisms are verified, ensuring that the calculator raises
appropriate errors for invalid operations (e.g., division by zero, invalid square
roots).
Example of test results:
----------------------------------------------------------------------
Ran 13 tests in 0.004s
OK
Discussion
1. Ease of Use:
o The application provides a user-friendly GUI that makes it easy to perform
calculations with a few button presses.
o Unlike traditional calculators that use physical buttons, the digital interface
allows for clear input and result display, making it easy for users to interact with
the application.
3. Error Handling:
o The calculator includes robust error handling for invalid operations. For
example, it raises errors when attempting to divide by zero or when taking the
square root of negative numbers.
o These error messages are displayed to the user, ensuring that the application
doesn’t crash and provides feedback on why the operation failed.
4. Performance:
o The calculator runs efficiently, with instant feedback provided for calculations,
even for more complex operations such as factorial or trigonometric functions.
o The error handling and input validation mechanisms ensure that the
application continues to run smoothly without crashes or incorrect results.
Limitations
1. Limited Functionality:
o While the calculator performs essential operations, it could be extended to
include more advanced mathematical functions, such as matrix operations or
statistical calculations.
o The calculator currently supports only basic mathematical constants and
functions. More advanced scientific or financial functions could be added in
future iterations.
2. GUI Limitations:
o The GUI is functional but could be enhanced further with more advanced
features such as a history log to track previous calculations, or an advanced
mode for scientific calculations.
o The design of the GUI is basic, and could be improved with more visually
appealing elements or additional customization options for the user.
3. Error Handling:
o Although the error handling for basic invalid operations is in place, there is
room to improve it further. For example, the calculator could handle more
complex errors, such as malformed input or unbalanced parentheses.
o Additionally, the error messages could be made more descriptive to guide the
user better.
Potential Improvements
1. Additional Mathematical Functions:
o Future versions of the calculator could include support for more advanced
operations such as matrix multiplication, integration, or differentiation.
o Implementing support for complex numbers or fractions would make the
calculator more versatile and suitable for more complex mathematical tasks.
2. GUI Enhancements:
o The GUI could be enhanced by incorporating interactive features such as drag-
and-drop or customizable themes.
o A more sophisticated layout with a scientific mode or unit conversion mode
could be added to meet the needs of more advanced users.
3. Performance Optimization:
o While the current performance is adequate for most calculations, adding a
multithreading or multiprocessing approach could speed up the computation
for larger or more complex calculations.
o Implementing a more optimized evaluation method (instead of using eval())
could also enhance performance and security.
Performance Analysis
1. Execution Time:
o The calculator responds quickly to inputs, with each operation typically
completing in milliseconds.
o The time complexity of each operation (addition, subtraction, multiplication,
etc.) is constant, ensuring that the calculator remains responsive for all inputs.
2. Scalability:
o The application can be extended to handle more complex mathematical tasks
or a larger set of operations, such as scientific calculations or unit conversions.
o Scalability is also achievable by optimizing the backend code to handle larger
input sizes or more complex algorithms.
3. Accuracy:
o The accuracy of the calculator's results is confirmed by the successful execution
of unit tests, which match expected outcomes for a wide range of
mathematical operations.
4. Visualization Efficiency:
o While the application is primarily focused on computations, adding
visualization features, such as plotting graphs for mathematical functions,
could enhance its functionality.
o Integrating libraries like matplotlib or plotly could allow users to visualize the
results of functions like sine, cosine, or exponential curves.
The Calculator Application with Unit Testing successfully fulfills its purpose of providing a user-
friendly tool for mathematical calculations. With a clean and functional GUI, reliable
functionality, and rigorous unit testing to ensure correctness, the application is well-suited for
both basic and advanced calculations. While there are opportunities for improvement in areas
like GUI design, error handling, and additional functionality, the current implementation offers
a robust and efficient solution for everyday calculations. Further development could focus on
enhancing the user experience and extending the functionality to cater to more complex
mathematical tasks.
Chapter 5: Summary, Conclusions, and Future Scope
for the Testing Calculator Project with Unit Testing
The Testing Calculator project was developed to create a reliable and functional calculator
with various mathematical operations, validated through unit testing. The primary aim of the
project was to build a Calculator class that supports basic arithmetic, advanced mathematical
functions, and error handling, integrated into a Tkinter-based graphical user interface (GUI).
The Calculator class includes operations like addition, subtraction, multiplication, division,
square root, trigonometric functions, and factorials, among others.
The project employed Python's unittest framework to validate the correctness of
mathematical methods and ensure the calculator handles edge cases and exceptions, such as
division by zero or invalid input. The GUI allows users to interact with the calculator by
inputting expressions and viewing results in real time. Manual testing of the user interface
was conducted to ensure seamless functionality between the GUI and the Calculator class.
Overall, the calculator serves as both a tool for everyday use and a robust system for
mathematical computation.
The Testing Calculator project successfully demonstrates the power of Python for creating a
simple yet powerful calculator with a user-friendly interface and a solid foundation in
automated testing. The key conclusions drawn from the project include:
5. Manual Validation:
o Manual testing of the GUI confirmed that all buttons are responsive, display
inputs correctly, and produce the correct results when pressed. Error messages
and validation were manually tested to ensure they are clear and user-friendly.
Future Scope:
While the Testing Calculator project is fully functional, there are several opportunities for
further enhancement and improvement:
2. Performance Optimization:
o Caching Results: For operations like factorials, especially for large numbers,
performance can be enhanced by caching results of previous calculations to
avoid redundant computations.
o Handling Large Numbers: Further optimizations could be made to handle large
numbers or computationally expensive functions efficiently, reducing the time
required for complex calculations.
3. Cross-Platform Compatibility:
6. Voice Commands:
o Integrating voice recognition could offer hands-free operation for users who
prefer voice commands for input. This feature could be particularly useful for
users with disabilities or those looking for greater accessibility.
8. Personalization:
o The application could be enhanced by allowing users to customize the
calculator's appearance, for example by changing themes, fonts, or layout
preferences. This would make the tool more appealing and adaptable to
different user preferences.
# Row 4 (4, 5, 6, *, -)
('4', 4, 0), ('5', 4, 1), ('6', 4, 2), ('*', 4,
3), ('-', 4, 4),
# Row 5 (1, 2, 3, +, /)
('1', 5, 0), ('2', 5, 1), ('3', 5, 2), ('+', 5,
3), ('/', 5, 4),
return expr
import unittest
import math
def test_add(self):
self.assertEqual(self.calculator.add(2, 3), 5)
self.assertEqual(self.calculator.add(-1, 1), 0)
def test_subtract(self):
self.assertEqual(self.calculator.subtract(5, 3), 2)
self.assertEqual(self.calculator.subtract(3, 5), -2)
def test_multiply(self):
self.assertEqual(self.calculator.multiply(3, 4), 12)
self.assertEqual(self.calculator.multiply(-3, 4), -12)
def test_divide(self):
self.assertEqual(self.calculator.divide(10, 2), 5)
with self.assertRaises(ValueError):
self.calculator.divide(10, 0) # Division by zero
should raise an error
def test_sqrt(self):
self.assertEqual(self.calculator.sqrt(16), 4)
with self.assertRaises(ValueError):
self.calculator.sqrt(-1) # Caannot take square
root of negative numbers
def test_power(self):
self.assertEqual(self.calculator.power(2, 3), 8)
self.assertEqual(self.calculator.power(5, 0), 1)
def test_percentage(self):
self.assertEqual(self.calculator.percentage(200, 10),
20)
self.assertEqual(self.calculator.percentage(100, 50),
50)
def test_factorial(self):
self.assertEqual(self.calculator.factorial(5), 120)
with self.assertRaises(ValueError):
self.calculator.factorial(-1) # Factorial is not
defined for negative numbers
def test_sin(self):
self.assertAlmostEqual(self.calculator.sin(math.pi /
2), 1)
self.assertAlmostEqual(self.calculator.sin(0), 0)
def test_cos(self):
self.assertAlmostEqual(self.calculator.cos(0), 1)
self.assertAlmostEqual(self.calculator.cos(math.pi), -
1)
def test_tan(self):
self.assertAlmostEqual(self.calculator.tan(math.pi /
4), 1)
with self.assertRaises(ValueError):
self.calculator.tan(math.pi / 2) # Tangent is
undefined at this angle
def test_exp(self):
self.assertEqual(self.calculator.exp(0), 1)
self.assertEqual(self.calculator.exp(1), math.e)
def test_log(self):
self.assertEqual(self.calculator.log(10), 1)
with self.assertRaises(ValueError):
self.calculator.log(0) # Logarithm is undefined
for zero or negative numbers
if _name_ == '_main_':
unittest.main(argv=[''], exit=False)