Create a new test project in the FindHighestNumber solution
We’ll draft out a test defining what we think we want the production code to do
Code Block language java public class TopicScoreWriterTest { @Test public void verify_topic_score_details_written_out_once() { // arrange String physics = "Physics"; ArrayList<TopicTopScore> topTopScores = new ArrayList<>(); topTopScores.add( new TopicTopScore(physics, 89)); TopicScoreWriter cut = new TopicScoreWriter(); // act cut.writeScores( topTopScores ); // assert } }
Line 10 represents the implementation class. We will call a method called
writeScores()
passing an arrayTopicTopScores
. Since this method will not return a result that is testable in this context, how are we going to test the result of thewriteScrores()
, it's going to make a call to a Java API. We are not going to test the Java API call, many millions of developers have already done this. We can use the mocking librariesverify
capability. But what are we going to verify?We’ll begin by decoupling the Java API call to write to the file stream from the TopicScorWriter. To do this could pass into the constructor a
java.io.FileWriter
object or something similar. But this would tie the production too tightly to java.io.FileWriter. Instead, let’s pass an object that encapsulates the file writer functionality. This object needs to support two capabilities 1) open a text file to write to, and 2) write the formatted string to the opened text file. With this design in mind, we can update our test and then dig a little deeper into the implementation code.Our updated test class now looks like this
Code Block language java namespace TopicWriterTests { interface IFileWriter { void WriteLine(String lineToWrite); } public class TopicWriterTests { [Test] public void Verify_topic_score_details_written_out_once() { // arrange String physics = "Physics"; String art = "Art"; String compSci = "Comp Sci"; String expectedResult = "Physics, 89"; TopicTopScore[] topTopScores = { new TopicTopScore(physics, 89) }; IFileWriter fileWriter = Substitute.For<IFileWriter>(); TopicScoreWriter cut = new TopicScoreWriter(fileWriter); // act cut.WriteScores(topTopScores); // assert fileWriter.Received(1).WriteLine(expectedResult); } } }
Notice the use of the interface at line 3. We then use this interface to create Mock object at line 18. At line 26 we are going to verify that the method WriteLine() is called once with a string formatted as shown at line 16.
Move the IFileWriter interfaces into the same file as
TopicScoreWriter
Code Block namespace TopicManagerService { public interface IFileWriter { void WriteLine(string lineToWrite); }
Let’s write the implementation code for
TopicScoreWriter
. We’ve used a canned result (line 20) to test our theoryCode Block language java public class TopicScoreWriter { private IFileWriter fileWriter; public TopicScoreWriter(IFileWriter fileWriter) { this.fileWriter = fileWriter; } public void WriteScores(TopicTopScore[] topTopScores) { fileWriter.WriteLine("Physics, 89"); } } }
Run the test and it should pass
We’ll now update
WriteScores()
so that it writes the data being passedCode Block language java public void writeScoresWriteScores(ArrayList<TopicTopScore>TopicTopScore[] topTopScores) { if ( topTopScores.size()Length > 0) ) { TopicTopScore tts = topTopScores.get([0)]; String string dataToWrite = tts.getTopicName()TopicName + ", " + tts.getTopScore()TopScore; itsFileWriter.writeLine fileWriter.WriteLine(dataToWrite); } }
The if statement introduces a new logic path in the code, we should have test for this
Code Block language java @Test [Test] public public void verifyVerify_empty_array_topic_score_details_not_written() { // arrange ArrayList<TopicTopScore>String physics = "Physics"; String art = "Art"; String compSci = "Comp Sci"; String expectedResult = "Physics, 89"; TopicTopScore[] topTopScores = new ArrayList<>Array.Empty<TopicTopScore>(); IFileWriter fileWriter = mock(IFileWriter.classSubstitute.For<IFileWriter>(); TopicScoreWriter cut = new TopicScoreWriter( fileWriter ); // act cut.writeScoresWriteScores( topTopScores ); // assert verify( fileWriter, times.DidNotReceive(0)).writeLine(Mockito.any()WriteLine(expectedResult); }
Finally, add another test that writes more top scores for different topics
Code Block @Test [Test] public public void verifyVerify_topic_score_details_written_out_multiple_times() { // arrange String string physics = "Physics"; Stringstring art = "Art"; String string compSci = "Comp Sci"; String string physicsResult = "Physics, 89"; Stringstring artsResult = "Art, 87"; Stringstring comSciResult = "Comp Sci, 97"; ArrayList<TopicTopScore> TopicTopScore[] topTopScores = { new ArrayList<>TopicTopScore();physics, 89), topTopScores.add( new TopicTopScore(physics, 89)); topTopScores.add( new TopicTopScore(art, 87));, topTopScores.add( new TopicTopScore(compSci, 97))}; String fileToWrite = "testfile.txt"; IFileWriter fileWriter = mock(IFileWriter.classSubstitute.For<IFileWriter>(); TopicScoreWriter cut = new TopicScoreWriter( fileWriter ); // act cut.writeScoresWriteScores( topTopScores ); // assert verify( fileWriter, times.Received(1)).writeLineWriteLine(physicsResult); verify( fileWriter, times.Received(1)).writeLineWriteLine(artsResult); verify( fileWriter, times.Received(1)).writeLineWriteLine(comSciResult); }
And the implementation code has been updated to
Code Block namespace TopicManagerService { public interface IFileWriter { void WriteLine(string lineToWrite); } public class TopicScoreWriter { private IFileWriter itsFileWriterfileWriter; public TopicScoreWriter(IFileWriter fileWriter) ) { this.itsFileWriterfileWriter = fileWriter; } public void writeScoresWriteScores(ArrayList<TopicTopScore>TopicTopScore[] topTopScores) { for( foreach( TopicTopScore tts :in topTopScores ) { String string dataToWrite = tts.getTopicName()TopicName + ", " + tts.getTopScore();TopScore; itsFileWriterfileWriter.writeLineWriteLine(dataToWrite); } } } }
Page Comparison
General
Content
Integrations