This content originally appeared on HackerNoon and was authored by Maximiliano Contieri
Transform manual hard-coded inputs into testable functions
\
TL;DR: Extract input logic into separate functions to make your code testable, with regressions and more maintainable.
Problems Addressed 😔
- Hard-coded inputs
- Testing difficulty
- Poor reusability
- Hidden dependencies
- Rigid and coupling implementation
- Untestable code
- Unnecessary input validation
- Hardcoded values
- Console side effects
- Poor regression
Related Code Smells 💨
https://hackernoon.com/how-to-find-the-stinky-parts-of-your-code-part-xxxviii
https://hackernoon.com/how-to-find-the-stinky-parts-of-your-code-part-xlvii
https://hackernoon.com/how-to-find-the-stinky-parts-of-your-code-part-i-xqz3evd
Steps 👣
- Identify code that uses direct input() statements
- Create a new function with a meaningful name
- Move input logic into the function with parameter options
- Add external validation and error handling
- Create unit tests for the new function
\ (If you follow Test-Driven Development, the step 5 becomes step 0)
Sample Code 💻
Before 🚨
n = int(input("Enter a positive integer: "))
# You need to make accidental castings
# And deal with obscure data types valitaciones
# which are a distraction for new programming students
if n <= 0:
print("Please enter a positive integer.")
else:
print(f"Prime factors of {n}:")
i = 2
while i * i <= n:
if n % i:
i += 1
else:
n //= i
print(i)
# You use global resources like the console
# And your code gets coupled from day one
if n > 1:
print(n)
# This example mixes data input and validation
# With algorithmic reasoning
# Violating the "separation of concerns" principle
After 👉
def prime_factors(n):
i = 2
factors = []
while i * i <= n:
if n % i:
i += 1
else:
n //= i
factors.append(i)
if n > 1:
factors.append(n)
return factors
# Step 1: Identify code that uses direct input() statements
# Step 2: Create a new function with a meaningful name
def prompt_positive_integer(prompt="Enter a positive integer: "):
# Step 3: Move input logic into the function with parameter options
try:
value = int(input(prompt))
# Step 4: Add validation and error handling
if value <= 0:
raise ValueError("Number must be positive")
return value
except ValueError as e:
if str(e) == "Number must be positive":
raise
raise ValueError("Invalid input. Please enter a number.")
def calculate_and_display_factors(number=None):
try:
if number is None:
number = prompt_positive_integer()
factors = prime_factors(number)
print(f"Prime factors of {number}:")
for factor in factors:
print(factor)
return factors
except ValueError as e:
print(f"Error: {e}")
return None
# Step 5: Create unit tests for the new function
import unittest
from unittest.mock import patch
class TestPrimeFactors(unittest.TestCase):
def test_prime_factors_of_12(self):
self.assertEqual(prime_factors(12), [2, 2, 3])
def test_prime_factors_of_13(self):
self.assertEqual(prime_factors(13), [13])
def test_prime_factors_of_20(self):
self.assertEqual(prime_factors(20), [2, 2, 5])
def test_prime_factors_of_1(self):
self.assertEqual(prime_factors(1), [])
class TestInputFunction(unittest.TestCase):
@patch('builtins.input', return_value='15')
def test_get_positive_integer_valid(self, mock_input):
self.assertEqual(get_positive_integer(), 15)
@patch('builtins.input', return_value='0')
def test_get_positive_integer_zero(self, mock_input):
with self.assertRaises(ValueError):
get_positive_integer()
@patch('builtins.input', return_value='-5')
def test_get_positive_integer_negative(self, mock_input):
with self.assertRaises(ValueError):
get_positive_integer()
@patch('builtins.input', return_value='abc')
def test_get_positive_integer_not_number(self, mock_input):
with self.assertRaises(ValueError):
get_positive_integer()
@patch('builtins.input', return_value='42')
def test_calculate_with_input(self, mock_input):
with patch('builtins.print') as mock_print:
result = calculate_and_display_factors()
self.assertEqual(result, [2, 3, 7])
def test_calculate_with_argument(self):
with patch('builtins.print') as mock_print:
result = calculate_and_display_factors(30)
self.assertEqual(result, [2, 3, 5])
Type 📝
- Semi-Automatic
Safety 🛡️
This refactoring is safe but requires careful testing.
\ Moving from direct input to function calls maintains the same behavior while improving structure.
\ Adding validation makes the code safer by preventing invalid inputs.
\ Each step can be tested independently, reducing the risk of introducing bugs and ensuring you have regression on previously tested inputs.
Why is the Code Better? ✨
You can test it without manual input by passing arguments directly to ensure regression of previous cases.
\ You can reuse the reified functions across your codebase.
\ You get clear error messages with proper exception handling.
\ You separate UI logic (getting input) from business logic (running the algorithm).
\ You make the code more maintainable by following the single responsibility principle.
How Does it Improve the Bijection? 🗺️
This refactoring creates a stronger bijection between the real world and your code by creating distinct functions that map to real-world actions (getting input vs. processing data)
\ You also add validation that enforces real-world constraints (for example, positive integers only)
\ In the bijection, it is essential to separate concerns that match actual domain boundaries.
\ The closer your code matches real-world concepts and constraints, the fewer bugs and surprises you'll encounter.
\ Dealing with input validation and modeling algorithms following real-world business rules are very different issues, and you should not mix them.
Refactor with AI 🤖
AI can help identify input calls throughout larger codebases and suggest appropriate function signatures and validation rules.
\
Suggested Prompt: 1. Identify code that uses direct input() statements 2. Create a new function with a meaningful name 3. Move input logic into the function with parameter options 4. Add external validation and error handling 5. Create unit tests for the new function
| Without Proper Instructions | With Specific Instructions | |----|----| | ChatGPT | ChatGPT | | Claude | Claude | | Perplexity | Perplexity | | Copilot | Copilot | | Gemini | Gemini | | DeepSeek | DeepSeek | | Meta AI | Meta AI | | Qwen | Qwen |
Tags 🏷️
- Coupling
Level 🔋
- Beginner
Related Refactorings 🔄
https://hackernoon.com/improving-the-code-one-line-at-a-time?embedable=true
Credits 🙏
Image by Spektrum78 on Pixabay
This article is part of the Refactoring Series.
https://maximilianocontieri.com/how-to-improve-your-code-with-easy-refactorings?embedable=true
\
This content originally appeared on HackerNoon and was authored by Maximiliano Contieri
Maximiliano Contieri | Sciencx (2025-04-07T05:44:51+00:00) Refactor Like a Pro: Ditch Hardcoded Inputs for Good. Retrieved from https://www.scien.cx/2025/04/07/refactor-like-a-pro-ditch-hardcoded-inputs-for-good/
Please log in to upload a file.
There are no updates yet.
Click the Upload button above to add an update.