Win a copy of Five Lines of Code this week in the OO, Patterns, UML and Refactoring 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
  • Ron McLeod
  • Jeanne Boyarsky
  • Paul Clapham
Sheriffs:
  • Tim Cooke
  • Liutauras Vilda
  • Junilu Lacar
Saloon Keepers:
  • Tim Moores
  • Stephan van Hulst
  • Tim Holloway
  • fred rosenberger
  • salvin francis
Bartenders:
  • Piet Souris
  • Frits Walraven
  • Carey Brown

implement vending application

 
Sheriff
Posts: 15779
264
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

s ravi chandran wrote:regarding the two test cases i was telling about, limited_product_quantity doesn't give useful info as to the purpose of the test?


I don't get what you're trying to say with "limited product quantity". They are all English words and individually, they have a meaning but taken together and in the context of the fill functionality, I don't know what the thought is behind it.

"Fill with limited product quantity"

"Wait, what?"

Maybe you meant "Fill with specific quantity" instead? That makes more sense to me.
 
Ranch Hand
Posts: 590
6
jQuery Java
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Junilu Lacar wrote:

s ravi chandran wrote:regarding the two test cases i was telling about, limited_product_quantity doesn't give useful info as to the purpose of the test?


I don't get what you're trying to say with "limited product quantity". They are all English words and individually, they have a meaning but taken together and in the context of the fill functionality, I don't know what the thought is behind it.

"Fill with limited product quantity"

"Wait, what?"

Maybe you meant "Fill with specific quantity" instead? That makes more sense to me.


ok. wrong selection of words... specific better suits the current context. apart from that, does the testcase look valid? i was thinking of following the user interface steps you had given to write the test case one by one:


1. Press "MAINT" button to enter maintenance mode
2. Press "REPORT" button to print report of current quantities
3. Press "FILL" button to fill up a tray to capacity, press "ENTER" or "CANCEL". Note down quantity displayed.
4. Optional: Press "FILL PART" button to partially fill a tray, enter quantity loaded then press "ENTER" or "CANCEL"
5. Optional: Press "REPORT" button to print report of current quantities after loading
6. Press "MAINT" button to exit maintenance mode


We have already covered testcases for fill and fill_part we can add now, after this only maintenance and report will remain.
 
Junilu Lacar
Sheriff
Posts: 15779
264
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

s ravi chandran wrote:wrong selection of words...


Yes, you now see how even one word out of context can make a big difference in comprehending what the program is doing.

We have already covered testcases for fill and fill_part we can add now, after this only maintenance and report will remain.


Like I said before, I think we've come to the limits of the responsibility of the VendingMachine class itself. Maybe one more method to query the remaining quantities in the trays so we can make a report. But the report and the other things will not be responsibilities of the VendingMachine. That should be with something else.

seems like a good test to write. Not sure I like the name getCurrentLevels very much but that's all I can think of right now.
 
s ravi chandran
Ranch Hand
Posts: 590
6
jQuery Java
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I added these for FILL_PART.

This will also go in other class? Names are a bit weird, but it does give its intended purpose.
 
Junilu Lacar
Sheriff
Posts: 15779
264
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
But before I go off and write more test code, I have to step back and look at the big picture again. How would the workflow go for the reporting function?

Let's say it goes like this:
1. Press the REPORT button
2. Machine displays "#1=6" which means tray #1 (only programmers are used to 0-based index) has 6 items left in it
3. Press ENTER, machine displays "#2=4"
4. Press ENTER, machine displays "#3=7"
... etc.
until it displays the last tray quantity.
5. Press ENTER or CANCEL, machine displays "Ready"
6. Press CANCEL at any time goes back to "Ready" mode

With this, it might be better to have "getCurrentLevel_returns_quantity_remaining_in_a_tray"
 
Junilu Lacar
Sheriff
Posts: 15779
264
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

s ravi chandran wrote:I added these for FILL_PART.


You have a test smell here. You should only test for one aspect of the behavior in a test method. This test checks two aspects: 1. Legal input and 2. Illegal input.

If you create two separate tests, the specification of the behavior is more focused and you adhere to the principle of separation of concerns

 
s ravi chandran
Ranch Hand
Posts: 590
6
jQuery Java
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Junilu Lacar wrote:

s ravi chandran wrote:I added these for FILL_PART.


You have a test smell here. You should only test for one aspect of the behavior in a test method. This test checks two aspects: 1. Legal input and 2. Illegal input.

If you create two separate tests, the specification of the behavior is more focused and you adhere to the principle of separation of concerns



Okay, got it. I initiallythought about it but I considered that boundary condition can also be considered with the same testcase..
 
s ravi chandran
Ranch Hand
Posts: 590
6
jQuery Java
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Need to check this:

getCurrentLevel_returns_quantity_remaining_in_a_tray

. what is it defining?
 
Junilu Lacar
Sheriff
Posts: 15779
264
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
And to make that more self-documenting, I would write:

Now, doesn't that make sense when you read it? Doesn't that specify exactly what the behavior is that we want? I also have 3 lines of code that are candidates for refactoring to remove duplication.

 
s ravi chandran
Ranch Hand
Posts: 590
6
jQuery Java
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
is it possible that REPORT gives current quantities of all the trays?

Like:

1. Press the REPORT button
2. Machine displays
"#1=6"
#2=8"
#3=5"
#4=0"
 
Junilu Lacar
Sheriff
Posts: 15779
264
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

s ravi chandran wrote:Need to check this:

getCurrentLevel_returns_quantity_remaining_in_a_tray

. what is it defining?


It says that the getCurrentLevel method of the VendingMachine class returns the quantity in the specified tray.

The second test is kind of pointless but if you're really anal about those kinds of things, like I am sometimes, I wouldn't mind it.
 
s ravi chandran
Ranch Hand
Posts: 590
6
jQuery Java
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Junilu Lacar wrote:



will this work? getCurrentQuantityForTray(FIRST_TRAY)
 
Junilu Lacar
Sheriff
Posts: 15779
264
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

s ravi chandran wrote:is it possible that REPORT gives current quantities of all the trays?

Like:

1. Press the REPORT button
2. Machine displays
"#1=6"
#2=8"
#3=5"
#4=0"


I imagine a simple one-line LCD display, like what you have in a calculator, only a little longer. Or you could have it scroll. Multi-line displays will cost more.
 
Junilu Lacar
Sheriff
Posts: 15779
264
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Just trying to keep it real, you know.
 
s ravi chandran
Ranch Hand
Posts: 590
6
jQuery Java
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Ok, I did not consider the limited view window. my bad.
 
Junilu Lacar
Sheriff
Posts: 15779
264
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

s ravi chandran wrote:will this work? getCurrentQuantityForTray(FIRST_TRAY)


Names like that tend to get redundant. I call it a "stutter" when you read it.

Read line 2 out loud and you'll hear yourself stutter the word "tray". I can accept getCurrentQuantityFor(tray) though. I still like the word "level" though. It fits with the words "fill" and "empty".
 
s ravi chandran
Ranch Hand
Posts: 590
6
jQuery Java
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
ok..
 
Junilu Lacar
Sheriff
Posts: 15779
264
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
This thread has again borne out the truth in my assertion that 90% of the improvements that you can make to code involve choosing better names, assigning responsibilities properly, and separating concerns. This corresponds to the refactorings to Rename, Extract Method, and writing well-composed methods.
 
s ravi chandran
Ranch Hand
Posts: 590
6
jQuery Java
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
This completes the functionality of vending machine right? we have covered all functions i think.
 
Junilu Lacar
Sheriff
Posts: 15779
264
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Well, there's a bit more code to be written to get a full simulation. But I think you should have a pretty good idea now. You really need to read up on the articles I cited about Design Principles SOLID, DRY, SLAP and keep those in mind. Most of all, practice, practice, practice.

I'll let you run with this now and will post feedback as you make progress (or make regressions ). Don't worry about making regressions, that's all part of the learning process. It took me a couple of years of solo TDD to really get a hang of it. It's tough without other people to set you straight but I read lots and lots of books and it's those guys who I kind of "partner" with. I just have a very good imagination -- I can make up conversations in my head. Some people call me crazy but it worked for me
 
s ravi chandran
Ranch Hand
Posts: 590
6
jQuery Java
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Junilu Lacar wrote:Well, there's a bit more code to be written to get a full simulation. But I think you should have a pretty good idea now. You really need to read up on the articles I cited about Design Principles SOLID, DRY, SLAP and keep those in mind. Most of all, practice, practice, practice.

I'll let you run with this now and will post feedback as you make progress (or make regressions ). Don't worry about making regressions, that's all part of the learning process. It took me a couple of years of solo TDD to really get a hang of it. It's tough without other people to set you straight but I read lots and lots of books and it's those guys who I kind of "partner" with. I just have a very good imagination -- I can make up conversations in my head. Some people call me crazy but it worked for me


Okay, will do. So far I came across the blind spots in my programming techniques. My software vocabulary needs lots of improvement, need better grasp of software simulation to get better user story breakups. I will work on the other part now. But from what I see, vending machine looks complete to me. Not sure what we are missing. Only thing remaining now looks like the customer simulation part. purchasing and balance processing etc.
 
s ravi chandran
Ranch Hand
Posts: 590
6
jQuery Java
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Okay, I am continuing further. Vending Machine is complete. Now what I think is needed is a class handling the user interface( not sure if it is essential ), a class handling customer request and a class handling the amount and balance amount.

from this I am taking the customer request handling as priority and I have added these user stories. Please check if this looks logical

1. Customer presses BUY to start purchase. ( can be removed if purchase window is always available)
2. Customer presses PRODUCT_AMOUNT and put the amount in money slot and presses ENTER/CANCEL.
3. Customer enters slot number of the product #slot and presses ENTER/CANCEL. ( not getting the term that is needed here )
4. if the amount is accepted then product will be available at take-out tray and remaining change will be available in money change slot.
5. if product is unavailable customer can choose another product by pressing RETURN and starting over
6. if customer doesn't want any other product or amount is rejected, he can press CASHRETURN to get his cash back in money change slot.

Here I have not added the option to enter quantity of product to be purchased. I believe we usually buy one item only and also, I am trying to keep it simple for now.

Any observation from this?
 
Junilu Lacar
Sheriff
Posts: 15779
264
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
If you really want to keep it simple, take cues from real-world vending machines. Here's the usual workflow:

1. Deposit coins until you have deposited enough or more than enough to buy at least one product.
2. Enter the Tray #, or Slot # if you like that better
3. Machine dispenses an item from that Tray or Slot
4. Machine gives back change, if necessary

The vendor interface does not have to be the customer interface. Imagine the vendor interface being hidden behind the machine door and it will only be exposed when the vendor opens up the machine for maintenance. The customer interface will only have a coin slot, a CANCEL button to cancel the transaction and return any coins deposited, and a numeric keypad to enter the Tray/Slot #. You could go fancy and say it was an Alpha-Numeric keypad, which some vending machines actually have, so that Trays/Slots can be identified as A1 or C4 or whatever, but go simple for now. Doing the fancy thing is easy once you have the simpler case working.
 
s ravi chandran
Ranch Hand
Posts: 590
6
jQuery Java
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Okay, will come up with a design. What should I name it? CustomerInteraction?
 
Junilu Lacar
Sheriff
Posts: 15779
264
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
"Customer Interaction" is kind of an abstract idea, like a "conversation". They're both nouns but they're not really physical things. I would try CustomerInterface, CustomerPanel, CustomerConsole or something like that.
 
s ravi chandran
Ranch Hand
Posts: 590
6
jQuery Java
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Junilu Lacar wrote:"Customer Interaction" is kind of an abstract idea, like a "conversation". They're both nouns but they're not really physical things. I would try CustomerInterface, CustomerPanel, CustomerConsole or something like that.


Am back. Ok, I thought about customerinterface, but this name might be confusing due to similiarity with the OOPS Interface. So, I will use the CustomerPanel. Will work on the class now.
 
s ravi chandran
Ranch Hand
Posts: 590
6
jQuery Java
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
added two test cases:


and


Any observation regarding this?
 
s ravi chandran
Ranch Hand
Posts: 590
6
jQuery Java
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
added more test cases and methods



 
Junilu Lacar
Sheriff
Posts: 15779
264
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
The test initial_amount_should_be_zero, which is a pretty good name, shows a strange API. Why would you have to call addAmount(0) to verify that the initial amount is 0? It's very unnatural and unintuitive. There's no such thing as a zero coin.

I can buy addAmount() returning the total amount added so far but for this test, I probably would think of something else for the API. Maybe a boolean hasCoinsDeposited() to check if there are any coins deposited or not and this simply returns true if the amount deposited so far is not zero. This would probably lead me to refactor the test name to something like hasCoinsDeposited_should_be_false_when_instantiated and follow-up with other tests:

hasCoinsDeposited_should_be_true_after_addAmount
hasCoinsDeposited_should_be_true_when_change_is_due
hasCoinsDeposited_should_be_false_when_no_change_is_due
hasCoinsDeposited_should_be_false_after_change_returned
.
 
Junilu Lacar
Sheriff
Posts: 15779
264
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
My naming convention for tests uses the actual method name being tested so I would probably refactor the test name:

from should_return_total_coins_entered
to addAmount_should_return_total_amount_deposited.

Remember, try to use the language of the domain; avoid "computer-speak" like "entered". Taking that advice, I'd try

deposit_should_return_running_total_of_coins_deposited which implies that you would refactor addAmount(int coinValue) to deposit(int coinValue) or something like that.

You're getting there. You have chosen some good names that reveal your intent. Just need to refine some of those choices a little more.
 
Junilu Lacar
Sheriff
Posts: 15779
264
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
If I had a test method

hasCoinsDeposited_should_be_true_after_addAmount and refactored the addAmount method to deposit, I would refactor this test name, too:

hasCoinsDeposited_should_be_true_after_deposit -- now your tests and method names are consistent. Also, hasCoinsDeposited() is more symmetrical to deposit() than addAmount().
 
Junilu Lacar
Sheriff
Posts: 15779
264
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
These other test names you have are not as well chosen; they don't convey your intent very well:

should_not_valid_coin -- not grammatically correct; makes me go . Also, it's not a very interesting test because there are no coins that I know of that have negative values. What would be more interesting might be a vending machine that didn't accept pennies (1 cent coins) but only accepted 5-, 10-, and 25-cent coins. Don't write tests just because you can; write tests that are meaningful. A test with negative coin values is kind of a nonsense test and has little value, IMO.

initial_slot_number -- again, the test name does not convey a complete thought. What about the initial slot number? You might as well have named this test "my_mother_in_law". Make the test name explain an aspect of the API or what's going on when you exercise the API. See the other names I have given so far.

select_slot_number -- same thing here, there's not a complete thought conveyed by this name; it's just a directive phrase. Also, if they access a private instance member directly, it's not really worth the effort to test getters and setters. I usually leave these as the 20% or so of code that I don't really need to test.

I target 80% to 90% code coverage for unit tests. Trying to achieve more than that usually gives diminishing returns for the effort you put in.
 
Junilu Lacar
Sheriff
Posts: 15779
264
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I have to give it to you, s ravi chandran, you have come a long way from your initial code. Just going back to what you first posted and what you have now, there has been a VAST improvement in how your code communicates what you're thinking and how organized that thinking is becoming. Keep up the good work! As added motivation for you, I will give you a cow for your efforts with the next code that you post that shows improvement
 
Junilu Lacar
Sheriff
Posts: 15779
264
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Junilu Lacar wrote:This would probably lead me to refactor the test name to something like hasCoinsDeposited_should_be_false_when_instantiated and follow-up with other tests:

hasCoinsDeposited_should_be_true_after_addAmount
hasCoinsDeposited_should_be_true_when_change_is_due
hasCoinsDeposited_should_be_false_when_no_change_is_due
hasCoinsDeposited_should_be_false_after_change_returned
.



As you come up with these tests and continue to do refactoring as you go, you should notice some patterns emerging in your test code. You will be doing certain things over and over again. Eliminating duplication in your test code is part of the refactoring step so I would imagine that you would end up with tests that look something like the following after several rounds of refactoring:

Don't try to get to this code right off the bat. You should get to this after a number of rounds of refactoring and only when you see patterns of duplicated code in your tests. Besides, if you try to code like this right off the bat, you deprive yourself of the satisfaction of seeing your code slowly become more beautiful. There's a lot of pleasure and satisfaction in seeing your initial code transforming into something that's as expressive as the above.
 
s ravi chandran
Ranch Hand
Posts: 590
6
jQuery Java
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
will check these points and make the changes in my code. I might have ignored refractoring a few times.. will remember next time. good meaningful method names will come from practice i hope.
 
s ravi chandran
Ranch Hand
Posts: 590
6
jQuery Java
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi,
I am working on what you said. I did not get this point:

Also, if they access a private instance member directly, it's not really worth the effort to test getters and setters

. Should I remove the initial slot and selected slot test cases?
 
s ravi chandran
Ranch Hand
Posts: 590
6
jQuery Java
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Changed the following:





I will verify the changed I made. I hope the new variable and method names look reasonable.
 
s ravi chandran
Ranch Hand
Posts: 590
6
jQuery Java
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Made slight change:


This way we will get the returning amount and changes will be reflected in total amount. This can be used to show it on the print screen.
 
s ravi chandran
Ranch Hand
Posts: 590
6
jQuery Java
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Added new test case and some modifications:





Any feedback about these changes?
 
Bartender
Posts: 1810
28
jQuery Netbeans IDE Eclipse IDE Firefox Browser MySQL Database Chrome Linux
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
What an excellent thread! I learned a great deal. Have a cow, Junilu.

In all honesty, I don't do TDD even though I know I should. I'm going to read the links posted and find a project that I can practice on. One of the things that has stopped me in the past is that all of my apps involved database access and I have never been able to figure out how to mock the database connection. It's time I learned.
 
We find this kind of rampant individuality very disturbing. But not this tiny ad:
Building a Better World in your Backyard by Paul Wheaton and Shawn Klassen-Koop
https://coderanch.com/wiki/718759/books/Building-World-Backyard-Paul-Wheaton
    Bookmark Topic Watch Topic
  • New Topic