...
The HighestNumberFinder
is designed to return an integer representing the number in a group of numbers. This can easily be stubbed out.Here is the Stub
Begin by creating a new test
Code Block | ||
---|---|---|
| ||
namespace TopicManagerService {[Test] public class HighestNumberFinderpublic void find_heighest_score_with_array_of_one_return_array_of_one_using_stub() { { public int findHighestNumber(int[] values) // {Arrange returnint[] scores = { 56, 67, 45, 89 }; } } } |
But when you try and use this class in the tests, you should see type errors. This is because, in the implementation unit of TopicManager
, it's typed against HighestNumberFinder
in a namespace called FindHighestNumberService.v6
. So namespaces do not offer us the solution we are looking for.
Here are the modified tests
Code Block | ||
---|---|---|
| ||
using NUnit.Framework; namespace TopicManagerService { public class TopicManagerTests { [Test] string topicName = "Physics"; TopicScores[] topicScores = { new TopicScores(topicName, scores) }; IHighestNumberFinder hnf = new TopicManagerServiceStubs.HighestNumberFinder(); TopicManager cut = new TopicManager(hnf); TopicTopScore[] expectedResult = { new TopicTopScore(topicName, 89) }; public void find_heighest_score_in_empty_array_return_empty_array() { // ArrangeAct TopicScoresTopicTopScore[] topicScoresresult = Arraycut.Empty<TopicScores>findTopicHighScores(topicScores); HighestNumberFinder hnf// =Assert new HighestNumberFinder(); TopicManager cut = new TopicManager(hnfAssert.AreEqual(result[0].TopicName, expectedResult[0].TopicName); TopicTopScoreAssert.AreEqual(result[0].TopScore, expectedResult = Array.Empty<TopicTopScore>([0].TopScore); } // Act TopicTopScore[] result = cut.findTopicHighScores(topicScores); } |
Here is the Stub. We have put it in a different namespace in the test project
Code Block | ||
---|---|---|
| ||
namespace TopicManagerServiceStubs { public class HighestNumberFinder { // Assert public int findHighestNumber(int[] values) Assert.That(result, Is.EqualTo(expectedResult));{ } return 89; [Test] } public void find_heighest_score_with_array_of_one_return_array_of_one() { } } |
But when you try and use this class in the tests, you should see type errors in all the tests. This is because, in the implementation unit of TopicManager
, it's typed against HighestNumberFinder
in a namespace called FindHighestNumberService.v6
. So namespaces do not offer us the solution we are looking for.
Here are the updated tests. Alternatively, you could modify TopicManager
so it has a default constructor, but you will need to think about different issues and more tests for if TopicManager
default constructor is used.
Code Block | ||
---|---|---|
| ||
using NUnit.Framework; namespace TopicManagerService { public class TopicManagerTests { // Arrange [Test] public int[] scores = { 56, 67, 45, 89 }; void find_heighest_score_in_empty_array_return_empty_array() { string topicName = "Physics";// Arrange TopicScores[] topicScores = { new TopicScores(topicName, scores) };Array.Empty<TopicScores>(); HighestNumberFinder hnf = new HighestNumberFinder(); TopicManager cut = new TopicManager(hnf); TopicTopScore[] expectedResult = {new TopicTopScore(topicName, 89)}Array.Empty<TopicTopScore>(); // Act TopicTopScore[] result = cut.findTopicHighScores(topicScores); // Assert Assert.AreEqualThat(result[0].TopicName, expectedResult[0].TopicNameIs.EqualTo(expectedResult)); } Assert.AreEqual(result[0].TopScore, expectedResult[0].TopScore); [Test] } } } |
Observe errors on lines 14 and 32.
We need to use interfaces. And the interface needs to be in a place that is available to both production code and tests.
...
Create a new interface that is part of the HighestNumberFinder
project
...
language | c# |
---|
...
public void find_heighest_score_with_array_of_one_return_array_of_one() |
...
|
...
|
...
{ |
...
|
...
// Arrange |
...
|
...
Copy HighestNumberFinder.v6 to HighestNumberFinderFinal
and refactor the class so that it implements the interface above
...
language | c# |
---|
...
|
...
|
...
|
...
|
...
|
...
int[] |
...
scores = { 56, 67, |
...
45, |
...
89 |
...
}; |
...
|
...
|
...
string topicName = |
...
"Physics"; |
...
TopicScores[] topicScores = { new TopicScores(topicName, scores) }; |
...
|
...
|
...
HighestNumberFinder |
...
hnf |
...
= new HighestNumberFinder(); |
...
|
...
|
...
TopicManager cut = new TopicManager(hnf); |
...
TopicTopScore[] expectedResult = {new TopicTopScore(topicName, 89)}; |
...
|
...
|
...
|
...
// Act |
...
|
...
TopicTopScore[] result = cut.findTopicHighScores(topicScores); // |
...
Assert |
...
|
...
|
...
|
...
Assert.AreEqual(result[0].TopicName, expectedResult[0].TopicName); |
...
Assert.AreEqual(result[0].TopScore, expectedResult[0].TopScore); } |
...
}
} |
To give us more flexibility, we need to use an interface. And the interface needs to be in a place that is available to both production code and tests.
Create a new interface that is part of the
HighestNumberFinder
production projectCode Block language c# namespace FindHighestNumberService { public interface IHighestNumberFinder { int result = values[i]findHighestNumber(int[] values); } } }
Copy HighestNumberFinder.v6 to
HighestNumberFinderFinal
Refactor the class so that it implements the interface above
Code Block language c# using System; using FindHighestNumberService; namespace FindHighestNumberServiceFinal { public returnclass result;EmptyArrayException : Exception { } } }
Refactor the tests so that the
HighestNumberFinder
is instantiated as followsCode Block IHighestNumberFinder hnf = new FindHighestNumberServiceFinal.HighestNumberFinder();
Refactor
TopicManager
so it now works with the interfaceIHighestNumberFinder
and not directly with the implementation classRerun all your tests they should still be passing.
Tip |
---|
The tests have given us the confidence to refactor the code and begin to think more clearly about our implementation. |
Now let’s substitute a stub in place of the real implementation of HighestNumberFinder
.
Create a new called
find_heighest_score_with_array_of_one_return_array_of_one_using_stub()
, it's a copy offind_heighest_score_with_array_of_one_return_array_of_one()
Code Block language c# public EmptyArrayException(string message):base(message) { } } public class HighestNumberFinder : IHighestNumberFinder { public int findHighestNumber(int[] values) { [Test] if (values.Length < 1) public void find_heighest_score_with_array_of_one_return_array_of_one_using_stub() throw {new EmptyArrayException("Array is empty"); // Arrange int result = Int32.MinValue; int[] scores = { 56, 67, 45, 89for };(int i = 0; i < values.Length; i++) string topicName = "Physics"; { TopicScores[] topicScores = { new TopicScores(topicName, scores) }; if (values[i] > result) IHighestNumberFinder hnf = new FindHighestNumberServiceFinal.HighestNumberFinder(); result = values[i]; TopicManager cut = new TopicManager(hnf); } TopicTopScore[] expectedResult = { new TopicTopScore(topicName, 89) } return result; } // Act } }
Modify the Stub version so it also implements
IHighestNumberFinder
Refactor
TopicManager
so it now works with the interfaceIHighestNumberFinder
and not directly with the implementation classCode Block language c# namespace TopicManagerServiceStubs { public class TopicManager TopicTopScore[] result{ = cut.findTopicHighScores(topicScores); private IHighestNumberFinder highestNumberFinder; // Assert public TopicManager( IHighestNumberFinder Assert.AreEqual(result[0].TopicName, expectedResult[0].TopicName);hnf ) { Assert.AreEqual(result[0].TopScore, expectedResult[0].TopScore); highestNumberFinder = hnf; } }
Modify line 8 to
The error is because of TopicManagerTestsCode Block language c# IHighestNumberFinder hnf = new TopicManagerService.HighestNumberFinder();
HighestNumberFinder does not implement the.
IHighestNumberFinder
interface. Modify it so that it does.Rerun the tests, they should all pass.
Rerun all your tests they should still be passing.
Tip |
---|
The tests have given us the confidence to refactor the code and begin to think more clearly about our implementation. |
Info |
---|
We’ve now created a controlled environment for our tests |
QLC-2.3 Limitations of Stubs, complete
...
this TopicManager
...
requirement
Add more tests to handle the last two requirements
•If the input is [{“Physics”, {56, 67, 45, 89}}, {“Art”, {87, 66, 78}], the result should be [{“Physics”, 89}, {“Art”, 87}]
Only one of the tests passes. Why?
QLC-2.4 Mocks, complete the last TopicManager requirement
•If the input is [{“Physics”, {56, 67, 45, 89}}, {“Art”, {87, 66, 78}}, {“Comp Sci”, {45, 88, 97, 56}}], the result should be [{“Physics”, 89}, {“Art”, 87}, {“Comp Sci”, 97}]