Win a copy of GANs in ActionE this week in the AI forum
or WebAssembly in Action in the JavaScript forum!
  • Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Bear Bibeault
  • Paul Clapham
  • Jeanne Boyarsky
  • Knute Snortum
Sheriffs:
  • Liutauras Vilda
  • Tim Cooke
  • Junilu Lacar
Saloon Keepers:
  • Ron McLeod
  • Stephan van Hulst
  • Tim Moores
  • Tim Holloway
  • Carey Brown
Bartenders:
  • Joe Ess
  • salvin francis
  • fred rosenberger

Testing with a factory method

 
Ranch Hand
Posts: 120
1
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
So I've read clean code and the 4 principles of simple design books. They are super helpful and I feel like I will be referring to them / rereading them for a while. I also have refactoring to patterns, working effectively with legacy code, test driven development, and fowler's refactoring book and on the way. I'm sure it'll take me a while to get through them and fully understand.

However I am beginning to see the benefits of tdd in regards to application design.

Now I've got a question regarding the factory pattern...

Currently I've got an abstract class AbstractRequest which provides a generic implementation for communicating with external APIs.


Then I've got another abstract class which represents an external service


Then I have implementations for each endpoint


My original thinking was that AServiceRequest would have static factory methods to return the appropriate class for the api call to be executed


Then I would have a class as follows:


However I'm think that isn't the best design, as I'm not sure how to stub the execute() return value in a test of myClass.

Would the factory pattern be a better design? Then I would pass the factory into the myClass constructor. This seems like it would allow me to easily stub the execute() response, making testing easier.

I'm thinking the factory would be a central location to get the appropriate AServiceRequest subclass for the desired endpoint call. such as:


But this seems like it maybe isn't the Factory method as I'm not returning a AbstractRequest or AServiceRequest but an implementation class.

Is there something I'm missing that will make this difficult to test? Is this something other then the factory method?
 
Sheriff
Posts: 14740
245
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
If you really want to see the power of TDD in driving out a better design, start by forgetting about everything you're thinking about now, refocus on what you want to achieve without knowing anything about the internal implementation then, in a test, write the code you wish you could write as a client of your application.

Force yourself to think about what would make the client code programmer's life really easy. I find that helps you cut out all the noise your overengineering brain likes to make and discover the simplest possible API that helps your clients get things done with minimal pomp and ceremony.
 
Rj Ewing
Ranch Hand
Posts: 120
1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Do you start at the high level function, and work your way down?

If I know I want to do X, and to do that I need to interact with an external api, my database, and do some business logic....

I would start with the api for X, and address the details as needed? One thing that confuses me a bit is what is the process when you need another class? Do you finish working on the current class, mocking out the new class, then when finished with the current, move to the new? Or should I start working on the new class immediately?
 
Junilu Lacar
Sheriff
Posts: 14740
245
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Have you ever seen the movie "Unforgiven"? I like that scene where the biographer W.W. Beauchamp is asking William Munny who of the five men he just shot did he kill first, then starts to explain to Munny how "When confronted by superior numbers, an experienced gunfighter will always fire on the best shot first" and Munny just looks at him coldly and says, "Is that so?"

Those questions almost sound like "Who'd you kill first?"

I can't really say one way or another, especially since I know so little about the context that you're working with. I guess in all fairness though, when I do TDD, I generally start from a high-level context and work my way downwards to more and more detail. I'll usually pick a class that "feels" like it will be architecturally significant or central to the overall design. Things don't always work out that way though. Sometimes you start with a class you think is significant but then learn more about the problem and end up going a whole 'nother way. It's a pretty fluid process and it can change directions at any time. Uncle Bob's Bowling Game TDD session with Bob Koss has one such turn. The nice thing about TDD is that you can explore one avenue and then when you get to dead end, you can easily backtrack and start exploring other ways to reach your goal.

My metaphor in doing TDD is usually "telling a story." If a subplot (a feature/set of object interactions) doesn't fit the main plot or the characters (my objects) don't work in a scene (a use case or user story), then I start looking at different ways to tell the story. I can't think of how you'd define a formula for this kind of process. It's more like weather forecasting really: you have to look at patterns, trends, and keep making adjustments in the face of the prevailing conditions and changes that you can measure in the moment. To me, programmers who don't do some form of TDD are like meteorologists who don't even have so much as a Weather Rock.
 
Rj Ewing
Ranch Hand
Posts: 120
1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Would you consider it a code smell if we have to use Fake objects when testing? Or more specifically a Fake object returning Fake objects?

After using tdd with parts of the system that will use the code in the 1st post. I've seem to come to a design that uses a Factory to return the appropriate API Endpoint Request.

Then in tests I can provide a FakeFactory.

This FakeFactory will provide Fake Api Endpoint Request, where I can pass in an expectedResponse and return it with the execute() method.
 
Junilu Lacar
Sheriff
Posts: 14740
245
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Rj Ewing wrote:Would you consider it a code smell if we have to use Fake objects when testing?


It really depends on how you use them. I don't think there's a general rule against faking things out. They can be code smell in some cases, in other case they're helpful. I think the sign you need to watch for is too much or too complicated setup code. If faking something gets too involved and your tests start smelling of complexity, then try to find ways to simplify. Again, the principles you fall back on are Simplicity and Clarity.
 
I'm sure glad that he's gone. Now I can read this tiny ad in peace!
Sauce Labs - World's Largest Continuous Testing Cloud for Websites and Mobile Apps
https://coderanch.com/t/722574/Sauce-Labs-World-Largest-Continuous
  • Post Reply Bookmark Topic Watch Topic
  • New Topic
Boost this thread!