What you think about having additional parameteriz...
# announcements
a
What you think about having additional parameterized constructor that would be used to pass in mock objects for unit testing only? Would you consider it a bad design since test only code is being inserted to production code? I’m working on a very small project and do not want to add the complexity of a dependency injection framework and thinking about injecting mocks into the class this way only when doing unit testing. Wondering if people find this as a bad design. Another way would be
@VisibleForTesting
annotation to assign mocks to variables directly but I find injecting mocks via the constructor is easier to read and clarify which objects needs to be mocked.
s
what do you mean, pass in mock objects for unit testing only? generally when you are mocking things you only mock what is passed into the constructor in the first place. why would you need to add a separate parameterized constructor?
a
Well I create an instance of classes that I need in the class itself and do not need to have it passed in. I want to replace this with mock objects during testing.
s
can you post a code example?
a
Copy code
class OtherClass(var s: String)

class BeingTested {

    lateinit var otherClass: OtherClass

    init {
        if(!::otherClass.isInitialized)
            otherClass = OtherClass("normal")
    }

    constructor()

    constructor(other: OtherClass) {
        this.otherClass = other
    }

}

var normal = BeingTested()
var mocked = BeingTested(other = OtherClass(("mocked")))

print(normal.otherClass.s)
print(mocked.otherClass.s)
Here is a sample.
normal would print normal and mocked would print mocked
s
why does your class not take it in the original constructor?
a
I can change it so it could do that assigning a default value. OtherClass does not need to be passed in. I just want to change it to a mock when testing.
Copy code
class OtherClass(var s: String)

class BeingTested(var otherClass: OtherClass = OtherClass("normal")) {
}

var normal = BeingTested()
var mocked = BeingTested(otherClass = OtherClass(("mocked")))

print(normal.otherClass.s)
print(mocked.otherClass.s
Here is a simplified example that uses a default parameter. The point of my question is since I only use it to pass in a mock object would you consider this a bad design?
BTW. Thanks for taking the time to look at this.
s
I think that if you are using an internal class like that and you need to mock it then something else is designed wrong. Here are the questions I would be asking myself (modifying production code to make it testable indicates a code smell to me)
1. Do you need this internal class?
2. Why do you need it?
3. Why can't it be passed in?
4. Can a setter be used instead of an overridden constructor?
a
1. yes. 2. It is required to implement feature for the given class 3. the external class or code does not know or doesn’t need to know about the OtherClass
4. Setter is also possible but again same question applies as it will be just used for testing.
s
if external classes don't need to know about it then why do you need a mock?
it seems there's a bit of an XY problem going on here, maybe if you describe the actual problem I can better help.
a
Unfortunately I cannot share the actual code. So there are some dependency and since the OtherClass is not what I want to test and also it is bit problematic to run. Let’s just say it does some network requests so would not want to run it in a unit test.
s
sounds fine, it seems like you should be passing it in as a parameter though, not just for testing, but always. That way you can switch it out if you want.
You don't need to write/use a DI framework for it though
just pass it in in all the places you use it.
a
Thanks. I could take various approaches to this but just wanted a quick opinion on the above approach from a good design perspective.
s
You can also just use the 'Simple Factory' pattern. Create a wrapper class that instantiates your above class and passes in the proper OtherClass.
a
👍 Thanks for the link.
s
np