Notes on Style Testing the TicTacToe game Jan 14 2019 A first approach I want to create a large number of tic tac toe partial games for testing purposes I could do it this way char array array new char X O X O O and I could reset the array for each tic tac toe board I want to use as input This looks nice and is easy to read but it is a real nuisance to type out a lot of these So I did this instead setBoard o x o o private void setBoard String xxx xxx xxx toUpperCase for int i 0 i 3 i for int j 0 j 3 j array i j Character toUpperCase xxx charAt 3 i j Now it s a lot easier to create tic tac toe boards for testing Morals Use methods to make your life easier If something is ugly hide it in a method Also While our main goal should be to write programs that are easy to read it isn t our only goal The best thing to do with hard to read methods is to rewrite them Second best is to explain them in comments I didn t include the comments on the slide but they are in my code Refactoring Refactoring is reorganizing a program without changing what it does Refactor in order to Make a program easier to understand Make a program easier to modify Before refactoring public final void testMakeCornerMove setBoard oxoxxoxo computerPlayer makeMove board assertBoardIs xoxoxxoxo setBoard oo xxooxx computerPlayer makeMove board assertBoardIs ooxxxooxx setBoard oxoxxoxo computerPlayer makeMove board assertBoardIs oxoxxoxox I seem to be doing the same thing over and over After refactoring private void beforeAndAfterMove String before String after setBoard before computerPlayer makeMove board assertBoardIs after public final void testMakeCornerMove Center and all other corners taken beforeAndAfterMove o x o o x o x o o beforeAndAfterMove o x o o o x x o o beforeAndAfterMove o o x o o o x o x beforeAndAfterMove o o x o o o x x o Corner move is all that s left beforeAndAfterMove oxoxxoxo xoxoxxoxo beforeAndAfterMove oo xxooxx ooxxxooxx beforeAndAfterMove oxoxxoxo oxoxxoxox beforeAndAfterMove xxooxxxoo xxooxxxoo Moral The DRY principle Don t Repeat Yourself Every piece of data should have a single unique representation A man with a watch knows what time it is A man with two watches is never sure Segal s Law Example If you have a measure of distance don t keep it in two variables distanceInFeet and distanceInMeters keep it in one variable and use a method to convert to the other units as needed Each nontrivial operation should be represented by a unique piece of code Don t cut and paste code turn it into a method Variations in code can often be handled by a parameter list Corrections and updates are much simpler Testing for a winning move Here s one way to test for a winning move There are 24 combinations to test for if board get 1 1 X board get 1 2 X board get 1 3 board set 1 3 X return true This is why I made testing for a winning move optional Using a method would help some if winningMove 1 1 1 2 1 3 return true But that s still 24 error prone lines plus a method A bright idea For each location on the tic tac toe board Put an X in that location Check for a win with our computerHasWon method If it s a win that s our move Otherwise put a blank in that location and keep trying We can do something very similar for testing if we need to make a blocking move The code private boolean makeWinningMove TicTacToeBoard board for int i 1 i 3 i for int j 1 j 3 j if board isEmpty i j continue board set i j X if board computerHasWon return true board set i j return false This code works but An unexpected consequence Row Row Row Row Row Row Row Row Row Row Row Why did this happen I did check for a blank space before placing my X 1 1 2 2 2 1 2 1 2 2 3 column column column column column column column column column column column 1 2 1 1 3 2 1 2 1 3 2 is is is is is is is is is is is already already already already already already already already already already already taken taken taken taken taken taken taken taken taken taken taken In the set method of TicTacToeBoard if board row 1 column 1 error Row row column column is already taken I can only set a location if it is initially blank I never thought about erasing an X or an O Proposed solution Modify the set method Problem I asked you not to modify the provided methods Under these constraints my bright idea cannot be made to work Morals Insofar as possible methods should do a single thing In particular it s usually a bad idea to mix computation and input output in the same method If you mix computation and input output in the same method then you can t do the computation without also doing the input output Example In a previous assignment I specified methods findDayOfWeek to only do computation and findAndPrintDayOfWeek to call the former and print the results This allowed me to test your computations without getting a bunch of output Fix 1 for board set row column ch I could have made set return a boolean true if the location was set false if it wasn t boolean set int row int column char ch if board row 1 column 1 ch X ch O board row 1 column 1 ch return true else return false Disadvantage The user might not check the result Disadvantage I test for two things that could go wrong location is taken bad character and this doesn t distinguish between them Fix 2 for board set row column ch I could assert that the location is available and assert that the character is legal void set int row int column char ch assert board row 1 column 1 assert ch X O board row 1 column 1 ch Disadvantage Bad use of assert it should be used for things you believe to be true not for error checking Fix 3 and 4 I could throw an Exception for each error condition This is the best solution We haven t covered Exceptions yet I nearly forgot this one I could just skip error checking Big disadvantage No warning to the user if something is wrong The End
View Full Document
Unlocking...