So one very good use of interfaces in go, is to make writing
tests easy. If you can use an interface rather than a concrete
type, then it turns out there makes mocking things in test
extremely easy for you to do. For example, I've added to my shelter, a
package, here, a function called read and shout, and what it
does is it takes a file, obviously a concrete type
reads every line of that file and then shouts them. So it will
print them out or
all in uppercase and I've changed the my program so that it
accepts a file argument opens that file and then
shouts it to stand out. So if we just go ahead and build that
and then run it and I'll just shout food or go. I was it goes, line-by-line
everything turns into upper case so no real surprise about what it does. Now
if I run the tests for shout then I'm going to
discover that I need to write some tests for read and
Out and immediately I'm faced with the idea of okay well I need to create a temporary
file and I can do that because the OS package provides a way to create temporary files. I need to make sure I
delete it and you put something in the file. Sounds like a bit of a pain. When really what I
want to do is test the basic functionality. And so the way to do
that is to modify this so that it
doesn't use a concrete type, he uses an interface and obviously the simplest interface for
this is going to be an IO reader, and
so we'll just do that.
And now this is taking interface type and let's just build it.
We no longer need less here because we're not doing it but we need IO
because we're doing that and let's just check that it works.
Okay, that works exactly the same. I didn't notice, I didn't change anything else in the program. If I go back to my program,
I'm still passing in this file but because file is an IO reader. Then
this works correctly. And this now means that the tests we can be made a little bit more easy.
Now, it's gonna be a bit tricky to test this when this is printing to standard out. So I'm going to modify this a
little bit more so it can return a string.
And an error and will just gather up the
response like this. So rather than printing it, I'm going to gather
it like that. So now I've got the whole thing put together
and I'm going to add back in those line feeds.
I'm not going to need format anymore. And here I'm going to return the
gathered string and the error like that
at the other end. I'll just modify my program.
Set a time print.
Do this. So,
Let's be a little bit naughty and ignore the error and just assume everything went. Well,
as
ever, we have to remember to import everything correctly because go is rather strict about
Okay, so it works the same. So now I've got myself in a case where I think I can
safely write a unit test for this and so in here before I would
have had to get a file, save it right stuff to a deleted or sort of
thing, but now I can just use a test string. So let's make myself a test string
and this is going to be
Something like this and I just need to know your reader. Well, let's look in the
the strings package. There's this thing,
a new reader function, which takes a string and returns an IO reader, so
that's going to be perfect. So I'm going to bring in strings.
I do that. So we're going to say and we're going to do read
and Shout, I'm going to do it from strings
new Reader test string, so that that will
do what we wanted. That will actually do that, and it's going to reply with the string
and error.
Okay, so let's just make sure first of all we'll do make sure no errors that happened
that happened. Then I'll see that's bad.
That shouldn't happen. And then there's also the same thing about there being no lowercase, so let's just make
sure that we do that.
Okay, so read and Shout here, make two
errors, make sure there's no lowercase in
s.
And therefore got a nice little test using, just this new reader here
and let's just go test it. You got
it, runs correctly. What's nice about that is you use the interface. Now,
in this instance, I use one of the standard interfaces IR reader which is used all over the
place, but you can also find this technique useful in your own programs. You may find
that there's an instance where it's better to have an interface because in the test Suite,
you can then Implement some dummy version of an object Robin
instantiating some enormous.
Thing. The other thing you can do is that if you limit it to just
part of an interface, just the bits, you typically need. So for example, I O reader
you only need that then you can have tests which don't have to create some
gigantic object, some gigantic thing with all sorts of interfaces
and that allows you to really focus in on what you want to mock.