# Code Smell 293 - isTesting

> TL;DR: Avoid adding *isTesting* or similar flags.

# Problems 😔

- Leaky abstraction
- Non-Business code pollution
- Fragile Code
- Inconsistent behavior
- Hidden dependencies
- Difficult debugging
- [Boolean flags](https://maximilianocontieri.com/code-smell-62-flag-variables)
- Untrusted tests
- [Production dependant code](https://maximilianocontieri.com/code-smell-106-production-dependent-code)

# Solutions 😃

1. Remove [behavior Ifs](https://maximilianocontieri.com/refactoring-014-remove-if)
2. Use dependency injection
3. Model external services (Don't [mock](https://maximilianocontieri.com/code-smell-30-mocking-business) them)
4. Separate configurations
5. Isolate test logic
6. Maintain clean behavior boundaries

# Refactorings ⚙️

%[https://maximilianocontieri.com/refactoring-014-remove-if]

# Context 💬

When you add flags like *isTesting*, you mix testing and production code. 

This creates hidden paths that are only active in tests. 

Also, you don't cover real production code.

You risk shipping testing behavior to production, leading to bugs and unpredictable behavior.

# Sample Code 📖

## Wrong ❌

<!-- [Gist Url](https://gist.github.com/mcsee/55c3d81ffe4d3555663b24d02e10d433) -->

```rust
struct PaymentService {
    is_testing: bool,
}

impl PaymentService {
    fn process_payment(&self, amount: f64) {
        if self.is_testing {
            println!("Testing mode: Skipping real payment");
            return;
        }
        println!("Processing payment of ${}", amount);
    }
}
```

## Right 👉

<!-- [Gist Url](https://gist.github.com/mcsee/697d23ac26444ce0f2935535bc07460e) -->

```rust
trait PaymentProcessor {
    fn process(&self, amount: f64);
}

struct RealPaymentProcessor;
impl PaymentProcessor for RealPaymentProcessor {
    fn process(&self, amount: f64) {
        println!("Processing payment of ${}", amount);
    }
}

struct TestingPaymentProcessor;
impl PaymentProcessor for TestingPaymentProcessor {
    // Notice this is not a mock
    fn process(&self, _: f64) {
        println!("No payment: Skipping real transaction");
    }
}

struct PaymentService<T: PaymentProcessor> {
    processor: T,
}

impl<T: PaymentProcessor> PaymentService<T> {
    fn process_payment(&self, amount: f64) {
        self.processor.process(amount);
    }
}
```

# Detection 🔍

[X] Semi-Automatic 

You can detect this smell by looking for conditional flags like *isTesting*, *environment == 'test'*, *DEBUG_MODE*, and idioms like these. 

These indicate that testing behavior is leaking into the production code.

# Tags 🏷️

- Testing

# Level 🔋

[X] Intermediate

# Why the Bijection Is Important 🗺️

You need a clear separation between test and production code. 

When you mix them, you break the one-to-one [Bijection](https://maximilianocontieri.com/the-one-and-only-software-design-principle) between real-world behavior and the program. 

Since environments are real-world entities you need to explicitly model them in the [MAPPER](https://maximilianocontieri.com/what-is-wrong-with-software).
 
# AI Generation 🤖

AI-generated code often introduces this smell when you use quick hacks for testing. 

Some tools suggest flags like *isTesting* because they prioritize ease over proper design.

# AI Detection 🥃

AI tools can catch this smell if you configure them to flag conditional logic based on testing states.

## Try Them! 🛠

*Remember: AI Assistants make lots of mistakes*

> Suggested Prompt: Remove IsTesting method and replace it by modeling the environments

| Without Proper Instructions    | With Specific Instructions |
| -------- | ------- |
| [ChatGPT](https://chat.openai.com/?q=Correct+and+explain+this+code%3A+%60%60%60rust%0D%0Astruct+PaymentService+%7B%0D%0A++++is_testing%3A+bool%2C%0D%0A%7D%0D%0A%0D%0Aimpl+PaymentService+%7B%0D%0A++++fn+process_payment%28%26self%2C+amount%3A+f64%29+%7B%0D%0A++++++++if+self.is_testing+%7B%0D%0A++++++++++++println%21%28%22Testing+mode%3A+Skipping+real+payment%22%29%3B%0D%0A++++++++++++return%3B%0D%0A++++++++%7D%0D%0A++++++++println%21%28%22Processing+payment+of+%24%7B%7D%22%2C+amount%29%3B%0D%0A++++%7D%0D%0A%7D%0D%0A%60%60%60) | [ChatGPT](https://chat.openai.com/?q=Remove+IsTesting+method+and+replace+it+modeling+the+environments%3A+%60%60%60rust%0D%0Astruct+PaymentService+%7B%0D%0A++++is_testing%3A+bool%2C%0D%0A%7D%0D%0A%0D%0Aimpl+PaymentService+%7B%0D%0A++++fn+process_payment%28%26self%2C+amount%3A+f64%29+%7B%0D%0A++++++++if+self.is_testing+%7B%0D%0A++++++++++++println%21%28%22Testing+mode%3A+Skipping+real+payment%22%29%3B%0D%0A++++++++++++return%3B%0D%0A++++++++%7D%0D%0A++++++++println%21%28%22Processing+payment+of+%24%7B%7D%22%2C+amount%29%3B%0D%0A++++%7D%0D%0A%7D%0D%0A%60%60%60) |
| [Claude](https://claude.ai/new?q=Correct+and+explain+this+code%3A+%60%60%60rust%0D%0Astruct+PaymentService+%7B%0D%0A++++is_testing%3A+bool%2C%0D%0A%7D%0D%0A%0D%0Aimpl+PaymentService+%7B%0D%0A++++fn+process_payment%28%26self%2C+amount%3A+f64%29+%7B%0D%0A++++++++if+self.is_testing+%7B%0D%0A++++++++++++println%21%28%22Testing+mode%3A+Skipping+real+payment%22%29%3B%0D%0A++++++++++++return%3B%0D%0A++++++++%7D%0D%0A++++++++println%21%28%22Processing+payment+of+%24%7B%7D%22%2C+amount%29%3B%0D%0A++++%7D%0D%0A%7D%0D%0A%60%60%60) | [Claude](https://claude.ai/new?q=Remove+IsTesting+method+and+replace+it+modeling+the+environments%3A+%60%60%60rust%0D%0Astruct+PaymentService+%7B%0D%0A++++is_testing%3A+bool%2C%0D%0A%7D%0D%0A%0D%0Aimpl+PaymentService+%7B%0D%0A++++fn+process_payment%28%26self%2C+amount%3A+f64%29+%7B%0D%0A++++++++if+self.is_testing+%7B%0D%0A++++++++++++println%21%28%22Testing+mode%3A+Skipping+real+payment%22%29%3B%0D%0A++++++++++++return%3B%0D%0A++++++++%7D%0D%0A++++++++println%21%28%22Processing+payment+of+%24%7B%7D%22%2C+amount%29%3B%0D%0A++++%7D%0D%0A%7D%0D%0A%60%60%60) |
| [Perplexity](https://www.perplexity.ai/?q=Correct+and+explain+this+code%3A+%60%60%60rust%0D%0Astruct+PaymentService+%7B%0D%0A++++is_testing%3A+bool%2C%0D%0A%7D%0D%0A%0D%0Aimpl+PaymentService+%7B%0D%0A++++fn+process_payment%28%26self%2C+amount%3A+f64%29+%7B%0D%0A++++++++if+self.is_testing+%7B%0D%0A++++++++++++println%21%28%22Testing+mode%3A+Skipping+real+payment%22%29%3B%0D%0A++++++++++++return%3B%0D%0A++++++++%7D%0D%0A++++++++println%21%28%22Processing+payment+of+%24%7B%7D%22%2C+amount%29%3B%0D%0A++++%7D%0D%0A%7D%0D%0A%60%60%60) | [Perplexity](https://www.perplexity.ai/?q=Remove+IsTesting+method+and+replace+it+modeling+the+environments%3A+%60%60%60rust%0D%0Astruct+PaymentService+%7B%0D%0A++++is_testing%3A+bool%2C%0D%0A%7D%0D%0A%0D%0Aimpl+PaymentService+%7B%0D%0A++++fn+process_payment%28%26self%2C+amount%3A+f64%29+%7B%0D%0A++++++++if+self.is_testing+%7B%0D%0A++++++++++++println%21%28%22Testing+mode%3A+Skipping+real+payment%22%29%3B%0D%0A++++++++++++return%3B%0D%0A++++++++%7D%0D%0A++++++++println%21%28%22Processing+payment+of+%24%7B%7D%22%2C+amount%29%3B%0D%0A++++%7D%0D%0A%7D%0D%0A%60%60%60) |
| [Copilot](https://www.bing.com/chat?showconv=1&sendquery=1&q=Correct+and+explain+this+code%3A+%60%60%60rust%0D%0Astruct+PaymentService+%7B%0D%0A++++is_testing%3A+bool%2C%0D%0A%7D%0D%0A%0D%0Aimpl+PaymentService+%7B%0D%0A++++fn+process_payment%28%26self%2C+amount%3A+f64%29+%7B%0D%0A++++++++if+self.is_testing+%7B%0D%0A++++++++++++println%21%28%22Testing+mode%3A+Skipping+real+payment%22%29%3B%0D%0A++++++++++++return%3B%0D%0A++++++++%7D%0D%0A++++++++println%21%28%22Processing+payment+of+%24%7B%7D%22%2C+amount%29%3B%0D%0A++++%7D%0D%0A%7D%0D%0A%60%60%60) | [Copilot](https://www.bing.com/chat?showconv=1&sendquery=1&q=Remove+IsTesting+method+and+replace+it+modeling+the+environments%3A+%60%60%60rust%0D%0Astruct+PaymentService+%7B%0D%0A++++is_testing%3A+bool%2C%0D%0A%7D%0D%0A%0D%0Aimpl+PaymentService+%7B%0D%0A++++fn+process_payment%28%26self%2C+amount%3A+f64%29+%7B%0D%0A++++++++if+self.is_testing+%7B%0D%0A++++++++++++println%21%28%22Testing+mode%3A+Skipping+real+payment%22%29%3B%0D%0A++++++++++++return%3B%0D%0A++++++++%7D%0D%0A++++++++println%21%28%22Processing+payment+of+%24%7B%7D%22%2C+amount%29%3B%0D%0A++++%7D%0D%0A%7D%0D%0A%60%60%60) |
| [Gemini](https://gemini.google.com/) | [Gemini](https://gemini.google.com/) | 
| [DeepSeek](https://chat.deepseek.com/) | [DeepSeek](https://chat.deepseek.com/) | 
| [Meta AI](https://www.meta.ai/chat) | [Meta AI](https://www.meta.ai/) | 
| [Qwen](https://chat.qwen.ai) | [Qwen](https://chat.qwen.ai) | 

# Conclusion 🏁

Avoid using *isTesting* flags. 

Use dependency injection and model the environments to keep test and production logic separate.

# Relations 👩‍❤️‍💋‍👨

%[https://maximilianocontieri.com/code-smell-106-production-dependent-code]

%[https://maximilianocontieri.com/code-smell-62-flag-variables]

%[https://maximilianocontieri.com/code-smell-30-mocking-business]

%[https://maximilianocontieri.com/code-smell-242-zombie-feature-flags]

# Disclaimer 📘

Code Smells are my [opinion](https://maximilianocontieri.com/i-wrote-more-than-90-articles-on-2021-here-is-what-i-learned).

# Credits 🙏

Photo by [Christian Gertenbach](https://unsplash.com/@kc_gertenbach) on [Unsplash](https://unsplash.com/photos/child-holding-photo-of-lips-0qjPdSvIa-M)
        
* * *

> When you add testing flags, you undermine confidence in production.

_ Ward Cunningham_  
 
%[https://maximilianocontieri.com/software-engineering-great-quotes]

* * *

This article is part of the CodeSmell Series.

%[https://maximilianocontieri.com/how-to-find-the-stinky-parts-of-your-code]
