DEV Community

Discussion on: How to write testable code

 
jessekphillips profile image
Jesse Phillips

I appreciate your concerns for my lack of domain knowledge and disregard for principals you hold. But I have my concerns that you aren't adequately testing the original behavior, and this response only reaffirms you don't understand my concerns because you're only focusing on one part of the original code.

As for the domain knowledge, you mentioned a refactoring gone awry. I'm claiming the refactor should not happen, why is domain knowledge relevant when I still don't let the bad code through?

Thread Thread
 
ddarrko profile image
Daniel

The refactoring was necessary in order to make the code less tightly coupled and in order to allow it to be unit tested. Unit tests are impossible when I have concrete dependencies instantiated in my methods.

The unit tests for cover the business requirements and paths for this class. There would be a myriad of other tests covering the validation class but they are not relevant here.

Thread Thread
 
jessekphillips profile image
Jesse Phillips

I was not referring to the validation class. There is not enough code present to verify the correct validation is happening, sure you have tests in the validation class, but is that the class used?

Thread Thread
 
hopeseekr profile image
Theodore R. Smith • Edited

I hope you have learned a lot in the last three years. You totally lack understanding of LSP, SRP and testing in general, yet have a pompous attitude to boot.

Thread Thread
 
Sloan, the sloth mascot
Comment deleted
 
ddarrko profile image
Daniel

@Jessie - There is plenty of code present to verify the transition takes place and this is what we are testing.

I already provided the business requirements for the class. Which of these requirements does the code not test ?

There are two paths - both of these are adequately covered.

'sure you have tests in the validation class, but is that the class used?'

What do you mean by this - this demonstrates to me you do not understand how to write software. You can see from the code that the class is being used. It is injected and its responses determine whether the transition runs or not.

The actual validation in this case is being mocked because it is a dependency of this class.

Thread Thread
 
jessekphillips profile image
Jesse Phillips

Yes the validator is injected, but that is only the test code. Did the original calling code get updated to inject the correct class? I don't know because it isn't tested.

This is something a merge request for this refactor would answer (because the article is a tutorial) thus my comments that their is more happening then just tests being added.

Thread Thread
 
ddarrko profile image
Daniel • Edited

Of course the calling code would have been updated to inject the correct class. This has its own tests as well.

I didn't add it because at some point the tutorial has a boundary and short of showing every call from input to output (including my DI container and framework code) I'm not going to cover every eventuality in a short post.

The tutorial was simply taking a single class and making it more testable.

Thread Thread
 
jessekphillips profile image
Jesse Phillips

I do understand the challenge with writing a consice tutorial, I'm trying to point out there is still risk introduced by this refactor.

I would actually love to see how you test that the correct verification object is injected in a unittest, I personally don't know how I'd do it.

Thread Thread
 
ddarrko profile image
Daniel

I think you may still have a slight misunderstanding of the SOLID principles.

The validation object is type hinted on the constructor. If I attempted to pass any other object (one that does not implement the interface) I would throw an exception. The test in this case is to test the actual State Transition class. I have other tests at the level these classes are called. These are the tests that would pick up if I was passing an incorrect interface.

I could have type hinted against a concrete implementation of a validation class but we should avoid doing that and code to an interface where possible.

Thread Thread
 
jessekphillips profile image
Jesse Phillips

I understand the purpose of the interface, what I'm seeing is that code is changing and it's behavior is not expected to change. The interface does not define behavior, the validation class tests do, but I need to know the activation behavior has not changed. And this code change, by design, decouples the validation logic from the taking action logic.

Thread Thread
 
ddarrko profile image
Daniel

I think you need to go back and revisit your software engineering fundamentals.

Thread Thread
 
jessekphillips profile image
Jesse Phillips

The purpose of my comment is to get you to think about the implications of following those principles, especially when the modified code had no reason to change other than to meet those principles.

This comment sounds more like you don't want to defend what you did and hope that generic explanations of how to write code will explain why it is OK to modify untested code. I can tell you right now the first advice will be to write a unittest to test the existing code before you refactor.

Thread Thread
 
ddarrko profile image
Daniel

As has already been explained clearly in the post - it is impossible to write a unit test for the original code because dependencies were instantiated. How does one write a proper unit test for a piece of code that has hard-coded dependencies.

Your assumption that the code was not covered is interesting though because it actually was covered by feature/integration tests. The feature tests still passed after the refactor by the way. The feature tests took the calling code for the State Transition class - passed with concrete validators and data from the database and then verify that after we call the transition end point the actual record in the DB has transitioned as expected. But all of that is completely out of the scope of the original blog.

Your comments have read like someone who is learning about proper software architecture. The end points you have arrived at differ wildly to your initial (incorrect) assumptions. I will not respond to further comments about this now. It has proven pretty fruitless and I once again suggest you brush up on SOLID principles.