-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Getting Started with Interfaces and Mocks #3
base: master
Are you sure you want to change the base?
Conversation
8a78d46
to
359cd2e
Compare
We're going to start building the back end for a simple dice game. The first thing I've done is to create a really simple implementation of a six-sided die (D6). I've simply called it Die. Looking through that code, there are no predicates where logic flow could diverge, so I'm not really seeing anything that I need to write tests about. My test coverage tool isn't happy, but that's the topic of a different conversation (one we have here). The Die object is really simple. It has a Let's implement something we need to test. I'm even going to write the tests first! Another topic for another time. |
Now let's make the tests pass by implementing some code. |
And now we have passing tests for the IsValidRoll method. I'm feeling good about this! Let's add another method and some tests. One of the things we need to check is that if all five of the dice have the same value. We'll call that a five-of-a-kind. This is definitely an original game and not a rip-off some some existing game... |
[TestMethod] | ||
public void IsFiveOfAKind_AllDiceAreTheSame_ReturnsTrue() | ||
{ | ||
IEnumerable<Die> dice = null; //Uh oh... how do I create dice that are all the same? | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Uh-oh, I've run into a problem. The DIe class randomly generates its value when it is created or when I roll it. That value is read only (as I will maintain that it should be), so how can I create an IEnumerable where the dice all have the same value? This is one of the reasons that objects that use randomness can be difficult to test. This is where interfaces can come to our rescue.
Let's do a little refactoring...
In this commit, I've created an IDie interface and have refactored some code (especially in the functions I need to test) to use the interface instead of the concrete Die implementation. You can poke through the commit to see exactly what I've changed. Now that we have an interface we can use, let's create a Mock object in our testing project that implements IDie. Remember, we're not trying to test the functionality of our Die class, just the extension methods that use it. |
Ok, we've now implemented a version of IDie in our testing project that allows us to set its value. Now we can actually write tests for our |
Now I've added a couple tests for IsFiveOfAKind using our new SettableD6. I have a test where the five dice all have the same value and one where they don't. I've also thrown in a test where an exception is thrown if an invalid roll is passed to the method. Right now all the tests fail because we haven't implemented IsFiveOfAKind. Remember, before the use of the interface, we couldn't even WRITE these tests. Progress! Let's make them pass. |
And now all of our tests pass. I hope this information was helpful. Check back soon to see an example of how to use Mocking frameworks to make this kind of change even easier. If you liked what you saw here and would like to learn more, feel free to contact me at [email protected]! |
e0fb744
to
999b5e7
Compare
In this section, we'll have a basic discussion about using interfaces and mocks for testing.
The use of interfaces is a much larger conversation that applies to much more than simply testing. Prudent use of interfaces helps us create systems with much less coupling between components. This allows us to modify, maintain and test components much more easily.
Mocks, specifically, help with testing to allow us to independently test components that have dependencies without having the tests themselves require the dependencies. Dependencies can often be difficult to set up the way we want, or don't allow us to have complete control of the data we receive. Mocks can also help us when we're testing other things that we can't control like time or randomness.
Let's look at some concrete examples.