How do you write tests for things that aren’t that easy to write tests for?

Brian & Anthony get started answering this question.


Transcript for episode 46 of the Test & Code Podcast

This transcript starts as an auto generated transcript.
PRs welcome if you want to help fix any errors.


Welcome to Test and Code, a podcast about software development and software testing.

A listener named Tony sent in a question that is possibly terribly summarized by a how do you write tests for things that aren’t easy to write tests for? Of course, different types of applications have different test strategies, so there’s not a universal answer.

But to help me get started answering the question, I asked my friend Anthony Shaw to come on the show and we discuss it for a while. But I know some of you out there have experience and expertise around how to tackle this kind of problem and similar problems.

Listen to the discussion Anthony and I have about it and let me know if you have any techniques or tips you’d like to add there’s. Contact form on Test and Code. Send me a message on Twitter where I’m at. Briannaken.

Thank you to Patreon supporters for sponsoring this episode. And every episode, become a supporter by going to testincode.com. There’s a donate option in the menu special. Shout out to super hacker supporters Andrew Evan, Steven, Steve Jordan, and Oliver now on with the show.

Welcome to Test and Code and I’m here your normal host, Brian Hawkins. But I’ve got Anthony Shaw here. We, of course, had Anthony on before we talked about testing and DevOps, and it was very popular and a lot of people really appreciated that one. I enjoyed talking to Anthony. What I really wanted to focus on for a bunch of this episode is I got a listener that sent me an email and said, I’m just going to read this.

Let me bring it up.

It was from Tony and he said, how does one migrate their thinking and code writing style from not using or writing unit tests to writing and using unit tests?

And I’m going to jump in and substitute just automated tests because I think both are important, he says follows on. The reason I ask is that I work at a place where the Python framework was poorly written. Much of it cannot be used with Python tools such as Pylent, Pipelix, and various unit test frameworks. As such, I’ve learned to write some bad code very well, and I’m now in a different Department where Python isn’t very used very much, but I still write all of my tools in Python. That said, I don’t know how to write Python code that can be unit tested nor refactor my existing code to do the same. I have your book. Thank you, Tony, which is a great resource. If you’ve already been using unit tester knows it doesn’t help someone in my situation who is trying to learn how to write testable code. For example, if you have a function that’s called like add two numbers and returns the addition of two numbers, that’s no problem. I know how to test that, but most of my code doesn’t look like that, so that’s the gist of it.

I’m sorry I wasn’t intending the book to be just for unit tester knows people. I was hoping that people could approach it without knowing those.

But that’s what we’re going to try to tackle today is if your code isn’t simple, functional code, how do you test it?

So it’s a big topic.

Do you have any comments before we start? Tony. Tony. Anthony. Sorry.

It’s either Anthony or Anthony, depending on which part of the world you come on.

Well, what do you prefer?

I really don’t mind, because in the UK, which is where I’m from, then it’s Anthony that H is silent. But in Australia, where I now live, is Anthony. So I’ve had to just get used to being called Anthony.

Well, Anthony sounds fancier, so I’ll call you that.

Okay, we’ll go with that. Most people just call me ants, so that’s easy.

Okay.

Yeah, I read through that and looking at, I guess, some examples. So I tried to think of an analogy we could use for the episode, because I think that would help people understand the situation that many people face. And if you’re stepping into a fairly mature software project and it’s been written in a way which is testable, it’s difficult to empathize with people who are saying they basically have code, which is hard to test. So I was thinking of an app we could use as an analogy for this episode. And so if you imagine that someone’s written the Python script which generates pictures of dogs, now it’s many thousands of lines long, there’s no functions in there. It’s all basically just one procedural script from start to finish, and the code somehow generates pictures of dogs artificially. Now, I guess the only way you know whether it’s working or not is to look at the picture at the end and as a human say, does that look like a dog?

So the question is, how would you convert that into a set of automated tests? Because if you try to do an automated integration test, you’d have to actually teach the computer how to recognize a dog. Like that would be the first thing you’d have to do. And then you say, well, my code that I’m writing that’s going to have to recognize whether it’s a dog or not is closely coupled to the script that I’m writing which generates a dog. So if my dog detection test, it ends up being having similar or the same bugs as my other test as my application, then I haven’t really achieved anything by doing that. So I guess that’s paraphrasing the problem that the reader sent across to us. And I have definitely seen this in lots of apps and programs in the past where people claim that it’s hard to test and it basically is because they’ve written an application which is very procedural, it’s not really modularized very well.

And the output is really the only artifact you have to go by.

Okay, but let’s stick with this for just a little bit.

Is our dog generating program is it generating random dogs or is it generating dogs based on some input?

You specify the shade of the fur, maybe, and the breed maybe you could say you want a shitzu or a poodle and it would generate a dog for you. So, yeah, you get a couple of inputs and it would generate a dog picture.

Well, I’m assuming. Well, I’m jumping to a conclusion that if I give it the same input, it’s going to give me the same dog output.

If that’s not true, then it’s definitely hard to test. Then it may as well just be random.

But if you can predict, like if they can be able to generate the same dog over and over again, then we can think of the entire thing as a function and we can test its input and output and compare the output to known input to known output. Right.

You said you think that’s a good place to start, because let’s say that it’s generating a picture of a cat accidentally. If you provide the wrong species and you have that as your output and you program that into the test, you’re kind of adding a test to match against the wrong behavior. Or do you have to validate the output first?

Well, like, for instance, as an example, a lot of markdown conversion tests are a series of files with markdown snippets in them and HTML output of the expected output. And the test is run your converter on the markdown and make sure the output matches the expected output.

And those are reasonable for a lot of cases. That’s a reasonable at least regression test. It might not be good for testing new features, but it’s to make sure that as you add new elements or new types of dogs to convert to that the old ones are still working, and I’ve definitely used that before.

Yeah. So where would you start, Brian? Which test would you write first.

Right off the bat? Because I know partly where we want to go with this is to possibly break up the code into smaller pieces that are more testable in like their pipelineness or modularness into some sort of either.

An ideal function to test is something that has a functional test, like we said, like an ad is easy.

If you have a known data set, you know which kind of output it’s going to be. Now, hitting all the cases is difficult, or deciding which subset of cases to test is still a hard problem.

But I know we’re going to try to do that. So I would probably wrap the known input and output because when I’m refactoring the code, I don’t want it to change too much, I don’t want it to change his behavior. So some big high level with this input, I should get that output tests before I start chopping up the code into pieces to make sure that I’m not breaking the code while I’m chopping it into pieces.

And that’s what you call the regression test. So that’s to make sure that the application doesn’t get worse as you change it in the future.

Yes, it’s a form of regression test.

I don’t really know what that word means, because anything that’s not a structural test is kind of a regression test, unless it’s a test of new behavior. I guess.

I always used it to describe a test when we’re testing something that we already know works.

It’s not a particular site, it’s not like a unit test or an integration test. It’s just let’s test this thing. Yes, we know it already works. We’re not looking for bugs, it’s just let’s have a catch in place so that if we break this fundamental piece of the application that we don’t go backwards.

Yeah.

Let’s assume people know how to test simple functions. There’s other things you can do around this output that are non regression. So there’s like, for instance, if I give it valid data, it should produce a output. So you can test against that the file exists, the output exists at all, and then certain aspects of it. Like if we expect a JPEG, it should output a. Jpeg file. I’m assuming there’s a way to test for that.

Yeah.

And then, for instance, if you’ve got a converter for HTML, there’s HTML validators.

If you’re generating C Code, you can run it through a C Linter or something to make sure that the output doesn’t have egregious bugs in it, because you would assume your wizard that you’re writing that’s generating code for you isn’t generating bad code. So you could test against those possibly.

Anyway.

Yeah. Any other ideas?

Yeah, I’d probably test, like we say, the most obvious one first, which is checking that it produces an image.

I wouldn’t jump into trying to write tests, almost like a test harness or something that would actually look at the output and run it through some sort of validation stage just yet. I’d probably then check against common mistakes the user would fall into and make sure the application behaves in a nice way. So for the type of breed, for example, let’s say you passed one that didn’t exist.

Let’s make sure that it gives them a good error back. Like it handles it well.

It doesn’t just crash completely or produce a picture of a banana or something.

I’d probably write those kind of tests next.

So what would you call those types of tests giving it bad values, negative cases. So I’d probably write those next and not make them too fancy at first. Like, just start off with some really simple use cases. Like what happens if you provide no breed? What happens if you provide an Invalid breed?

Two breeds, and then.

Yeah, two breeds. There’s a whole bunch of different cases. And for Python, there are some libraries out there for bad data in particular, like Unicode values and weird date strings and stuff like that. I can’t remember the name of the package. I think you’ve mentioned it before. It’s almost like it’s a package full of input, basically static values that you can use for testing purposes, and they contain all sorts of weird things.

Well, I mean, there’s, like, Faker that produces all sorts of stuff. Is that what you’re thinking of?

No, I’ll come back to it anyway.

I remember that’s actually something people forget about a lot is to make sure that bad data produces a reasonable error message.

Yeah, because that’s the most likely thing that’s going to happen is that the user puts in the wrong value, and if that produces an Invalid image, let’s say so places where I’ve seen that really commonly is you basically have some sort of input. So whether that’s a web interface, a command line, or some sort of data processing, so you’re ingesting data from somewhere else, and then you’re running it through an application, and then it’s storing it in a database or storing it in some sort of caching layer or something. And what ends up happening is that you store Invalid data. So instead of handling the error like it should have done, it basically processes garbage and it produces a bad output, and then it stores that bad output, and then that basically has consequences for the system, because the system then reads that bad output from the database or from the cache, and then it crashes other layers or other components to the application. So that’s where I think good test cases at the beginning would check for Invalid inputs and make sure that they’re caught successfully and they’re handled properly and they’re not just propagated through the system.

Yeah, I think that’s good.

One of the other things I’ve done before is I’ve actually had quite a few cases where I’ve had to test something where I don’t really know how to test it yet. But I know, like, I’m adding another dial to the system, another input value, and I know it just has to have some change. Like, for example, let’s say we have a background color for our dog image.

I don’t really know how to test to make sure the background image is background color is correct, but I know that if I give it a different background color, the output should be different. So I can give it black, for instance, and get that output, and then I can change that input to the background to be blue, and those two images better not be the identical image.

That seems obvious in this case, but there are cases where you just want to make sure that one of the input values that you’re passing in actually has some effect.

When you expect it to have an effect, it needs to at least change the output in some way.

Yeah. And I guess you want to make sure that the test that you’re writing and providing value as soon as possible, especially if you’re working in an environment where people don’t see the value in tests or in testing itself, then writing lots of weird edge case error handling tests at the beginning kind of doesn’t really help, I say, in changing people’s perceptions. Like if you can write tests which find bugs early and quickly, then definitely you can help change people’s mindsets. Have you had any experience with that sort of situation before, Brian?

Yeah, definitely.

One of the places where we utilize throwing automated tests right away are areas of the code. So let’s say you’re using an application that a lot of people on the team use also, but there’s certain aspects of it that are not used that you can’t access readily from the user interface. And most of the team doesn’t use on a regular basis.

But you have certain customers that depend on it putting automated tests around those to make sure that little tiny changes don’t affect those because they’re not going to get caught until you’re doing a formal, thorough test of the entire system.

Yeah, I’ve definitely had cases like that catching little tiny things like we’re talking about. Even if you test after the fact of testing a system that you think pretty much works, running those between every little change. If you’ve got multiple teams running the same set of tests, when you’re integrating all the different pieces of code, after every little piece, we pull in code from Team A, then run the test, and then pull in the stuff that Team B delivered and then run the test. And those types of tests can isolate where the problem is so we can know where to throw the defect report to which team.

I mean, in the dog scenario, when would you and would you, I guess, start to write a test that actually looks at the picture and tries to determine whether or not it’s a dog? Like it looks at characteristics like it counts the number of legs, it looks for two eyes and two ears and the tail?

Would you actually go and write that kind of thing? Because I’ve definitely found I’ve been in those situations before. I can actually think of a package that I work on already, which is similar. It doesn’t create pictures of dogs, unfortunately, although that does sound fun.

It’s a Sphinx plugin, and it basically takes your Sphinx output and produces it in a format. So instead of HTML, which is what Sphinx normally generates, or PDFs, then it generates it in something for Latin Confluence, which is like a Wiki platform that Atlassian make, and they have their own proprietary storage format, which only Confluence understands.

And basically the Sphinx plugin will produce the output in a format that Confluence can use. So basically what you can do is take all your Restructured text and all your documentation, all your auto documented classes and stuff like that, you can use this plugin and then when you run Sphinx, it will basically generate the output and then upload it into your Wiki server.

And this has actually been pretty popular. This package, people have found it really useful for all their internal wikis, where you can’t just put it on Reader. Docs.

And running your own Reader. Doc server is extremely complicated.

So instead they’re using something like Confluence, which you can lock down for only internal people within a company.

So in terms of writing the tests, I guess I was in the same situation at the beginning, which was, well, I can’t test if it generates valid Confluence data, because I’ve got no way of doing that unless I actually go and write a Confluence data parser, basically reverse engineer the thing that I’ve just made.

So what I did instead was to kind of break it down into smaller components. So let’s check that it navigates the tree properly. Let’s check that it generates the header. Let’s check that it does numbered lists and tables and basically test all the individual components instead of trying to do one big test.

But yeah, I’d say that was kind of the most similar thing I’ve had to the Dog generator, where I kind of found myself questioning, why should I make a test that tries to actually look at the picture and determine if it’s a dog or not?

Yeah. And it’s unfortunate that at least I don’t have a lot of experience with testing actual images. But I was talking with Stephanie Herlbert once, and they do make like an image compressor thing and asked her about the testing, and they were looking at ways to automate it. But you can go pretty far with semi automation.

For instance, you can have, let’s say, generate like 100 different pictures of things that you think are supposed to be dogs and then 100 different non dogs, and you can set them up on like, you can set 20 pictures at a time or something on a screen and say, make sure all of these are dogs and actual humans. Check to make sure that your code is working.

It takes a while to get better than people and people time sometimes isn’t that bad to just hire people to make sure that your dogs are dogs and your non dogs are nondogs.

There is a place for manual testing still, especially if it’s cheaper than trying to figure out some AI system to figure out whether or not your pictures are dogs.

Yeah. And you’d have to train the AI properly as well. Like, if it would catch the app, creating a dog with three eyes or something.

Yeah. How successfully would it do that? Well, how successfully would a human do that? I guess that’s another question. But I know I’ve been in that situation as well.

I remember we’re producing a mobile application and we wanted to figure out how to do automated testing, but we had to test it against multiple versions of iOS and multiple versions of Android. And basically one of the solutions was we used a service from a testing provider. So there are actually companies out there that can test your stuff. You just pay them and they test whatever it is you want them to test.

And they have a service for mobile applications. And what they have basically is a bank of phones in a huge line, and they basically automate the Loading of the phones with the application.

And then they have another thing that basically interfaces with the screens and it actually goes through and clicks the buttons and stuff and does all the validation.

And then if you can’t produce a set of test steps which can be automated like that, then they have another option where you can basically pay for someone to go and press the buttons for you. So, yeah, that’s pretty common.

And then I think there’s a couple of other things we probably should get to the there’s some stuff that you really can’t test. You really want to test just your code and you can’t test it without the whole system in event driven architectures where your piece of code is relying on some event happening and then the output isn’t really output, it’s sending triggers to different parts of the system or something like that.

Those are places where it’s hard to isolate it.

It’s just hard to pick it apart and do that sort of mid level integration test without grabbing everything.

I don’t know why I brought that up, because I don’t really have an answer for that.

And then also, once we do start breaking the file up and making it into smaller pieces, how do you go about doing that?

Yeah, I guess you could look at characteristics of it.

In the case that the reader was sending in, it’s producing a proprietary output. So the format that it’s producing is like a type of bootloader.

So how would you test that? And I’d actually look at basically converting the process of creating the output into stages and then seeing how you would test each stage.

So that is essentially unit testing what you’re doing, but you’re looking at the whole thing as a process, as like a pipeline. And then you’re saying, okay, how can I split it up into logical stages?

And this is more of a refactoring mechanism that I’ve used in the past as well. When you look at either a really long function, something that shouldn’t be, it does 25 different things and it should really only do one or two.

How do you split that up into smaller components and then test each of the components? So that’s where I just use comments to put, step one, do this, step two, do that, step three, do this, and then actually think logically. How do you break it into stages and then can you decouple those stages? Like, which variables is that stage depending on if I move into a function, how would that work?

Now, in other languages and some ideas, you can actually highlight blocks of code and say, convert to a method or a function, and it’ll actually do all that work automatically for you, which is really helpful.

And the output is not always super clean. I’m pretty sure PyCharm can do that, because I know that the JetBrains tools and C Sharps can definitely do that. Resharper can do that. You can basically highlight blocks of code and say, make this a function, and then anyone that calls it it gets rereferenced. So it does a lot the refactoring work for you.

Neat.

Yeah. And then if you’ve got a stage or a step which has kind of been decoupled from the process and you know what the inputs are and you know what the outputs are, then you can test it. That’s a lot easier than trying to test whether or not as a dog. Now you’re just looking at how it calculates the width of the dog or the color, and you’re saying, given this input, does it produce yellow or Brown as the fur type?

Yeah.

Difference. And stuff like data pipelines are going to be similar to try to figure out which stages of a data pipeline, for instance, there’s different characteristics of different stages where you can test to make sure things are still not haywire.

I’m talking about this as if I know data science. I don’t. I’ve just talked to enough people that do it that I know that there’s a staging of data science as well.

I don’t think I’ve ever seen any testing in any of the data science stuff that I’ve seen. So I don’t know how they do that. Like how you would even write tests around something like a Jupiter notebook, for example.

If that’s even done.

I hope it’s tested.

Otherwise, we’ve got a lot of conclusions being drawn on the world on data science. That untested code, and that would be creepy.

The more I get into testing, the more I get into talking to different people about how they do it, the more of a miracle it is that all of the software that’s running the world right now still runs. But part of it is because people just manually test it. I mean, isn’t that things aren’t tested. It’s things that people manually test pieces of it while they’re developing it, and unless they run into cases where they didn’t think about it or they’re changing the code to apply to different situations where it really is not valid, usually that’s okay. I’m not one of those people that thinks that legacy code without test is necessarily terrible code. It may be dependent on a lot of different pieces, and it’s hard to pull it apart, but it doesn’t make it bad. If it’s producing valid output and making people money, that’s a good thing.

So when you’re writing tests, do you look at it as though you’re looking at something and trying to figure out how to test it, or are you looking at it and trying to find the bugs?

The finding bugs thing isn’t something that’s not where my mindset is.

I’m trying to validate or trying to find out if a piece of software is doing what it should be doing, if it’s being used as it’s intended to be used, and then also common mistakes, and looking at common mistakes or common places where developers tend to not think about the given when then strategy of behavior driven development works for me. I don’t use Gurkin, I use Python code and pytest code.

But the notion of saying breaking up a problem of given a certain situation, if I do one action or a certain system state, if I do one function call or one action or some method, then what output do I expect? And sometimes it’s actual output. It’s the output data, but often it’s changed to the system and the change to the system can be tested.

So those are the happy path pieces. But then I break apart each piece and say, is my given valid?

How many different given States are valid and Invalid? And what happens if I like in the case of turning on the engine, turning the ignition switch on a car, given that the engine is off? If you push the turn on the ignition, you should have an engine that’s on afterwards. What if it’s already on?

What’s the condition supposed to be then? And how do you test that?

What’s supposed to happen then?

And then also output?

I look at all the different kinds of output.

Is there Invalid output? And how do I produce that?

And then all of the air conditions, hopefully finding those air conditions and making sure that we know what those look like.

And that’s about where I stop usually. And that thought processor is really pretty quick, and it’s usually just me writing down a handful of test cases that should be written for a given piece of code and then just writing them and running it on the code and making sure that the output and the behavior seems reasonable. And then I move on testing other stuff.

And then when we run into problems, I throw more effort at testing pieces that give us trouble or pieces that there’s a lot of areas where you can focus more energy on.

Like for instance, if there’s a really complicated algorithm in the middle of something, then focusing some testing around that is a good idea.

And I do that also pieces that everybody seems to shy away from. And it’s code that’s like we don’t touch that much because every time we touch it, it breaks stuff.

Well, one I have a temptation to just say, well, we definitely need to completely rip that out and rewrite it then, because nobody should be scared of the code. But sometimes you don’t have time for that. So making sure that there’s some, like we talked about regression tests around that to make sure that known conditions that do crop up happen. Because it’s kind of fun to intentionally put in bad data because you need to be able to see what the output supposed to look like. And I’ve had several cases where you can’t detect it. A bad data is undetectable, and then we have to refactor part of the system to make sure the air conditions are not eaten and that they’re displayed correctly.

I’m biased, though, because I work in an environment where we produce test output like actual test equipment numbers and electronic companies are depending on those numbers. So the worst thing is not to crash. The worst thing is to give numbers that are wrong. I’d much rather crash the system than give a wrong number.

Now, that’s probably not the case for a lot of environments, but in my environment, that’s true. So we do lots of testing around our measurement data to make sure that our measurement values are correct. But anyway, there’s a long answer. Sorry about that.

That’s okay. And you would say you’re more of an optimist than in terms of your approach?

Well, things like I don’t know what you mean by optimist.

I don’t think there’s any developers in the system that are malicious. So it’s a closed system as well. So I don’t have to test against somebody trying to hack into the system or something since it’s not a network system, it’s a closed environment.

In terms of, like an optimist.

If I’m looking at testing something and assuming I’ve written, I go into it assuming that I’ve made mistakes. And my approach is basically I’m just trying to write tests to find where my mistakes are.

Okay.

I’d say that I’m a pessimist, whereas in your response, what you were describing is that you’re looking at in terms of the testing approach is you’re surrounding the application with almost, like padding and structure to give it to make sure that the inputs and outputs are correct and valid. So it’s a bit more optimistic in your approach.

Yes. I guess there’s a lot of bugs that can exist and still actually have functional software.

Yeah. That’s why I tend to shy away from unit test quite a bit, because there’s a lot of code that doesn’t handle corner cases very well, but there’s a lot of code that never hits the corner cases. So even if it doesn’t handle it very well, that’s probably okay.

I’m the kind of person that keeps me up at night thinking about overtesting because there’s maintenance cost to code, and it’s true of your test code just as much as your production code.

So if I put a test around a piece of the system to try to test all the corner cases and some of those fail, should I fix it?

And it depends kind of on can the end user ever hit those corner cases?

So if I can fail some code at a unit test level, but that failure cannot be reached from a system level, it’s a trade off.

Depends on how long. If it’s like a few minutes to fix the code, then go for it, fix it, but it’s not really broken as far as the system is concerned.

Yeah, okay, I see what you mean.

Like our dog generator.

If nobody actually ever tries to generate octopi with it.

If it breaks when you put in octopi and eight legs, that’s probably okay, because we don’t really need eight legged dogs.

Yeah, you could definitely do that a lot with Python, because you make a lot of assumptions in Python about the type which is being parsed. And I don’t see many tests that say, let’s check what happens if we send it instead of a string, we send it an integer or a list, or a tuple or an unexpected type. I don’t see many of those tests, and at the same time I don’t see a lot of statements at the top of function saying let’s check that the input is a string. Let’s check the input as a list, which in Python you’d say F is instance variable comma types.

I don’t see a lot of that code, whereas I do in weirdly enough, in more strongly Typed languages such as C, Sharp, and Java, for example, you typically have a lot of no reference checks at the top of each function.

I see that a lot less in Python, but a lot of the bugs that I see in Python are because of X is not a property of non type. So yeah, I don’t know if that’s a characteristic of the language. People are a bit more trusting or maybe even naive about typing and dealing with typing and writing tests that deal with bad or unexpected values.

Yeah. Like for instance. Okay, the properties of none comes up a lot, actually, because we’ve got actually came up last week. I had to talk with somebody about it because there was a test that failed and the failure stated that none cannot be dereferenced or you can’t take the index of it or something like that. And basically it’s because we were expecting a list to come back and trying to get the first element of the list and using the bracket operator, and you can’t do that on none.

If a list doesn’t come back and none comes back instead, it doesn’t work.

But Python is good enough that if you start looking at the trace backs, you can try to figure that stuff out. Not too bad.

Anyway, I think that we’ve probably generated a lot of ideas, and I’d like to have people get in touch with the show and with us to try to tell us other situations that maybe they’ve got better solutions or maybe they’ve got some other ideas of different things that we want to be able to test and like I said, if it’s an event driven system, I have no idea how to test that.

Maybe we could get somebody on the desk and then you’ve got like asynchronous code. I haven’t really got into trying to test asynchronous stuff but I guess it’s like I don’t know if you have black box type stuff.

I use Python to test multi threaded C applications so it shouldn’t be too bad.

I still haven’t managed to successfully write any asynchronous code in Python so let alone test it yeah.

Let’S leave that topic alone for a little bit. So one of the things is I want to have more episodes of test and code and I realized that I was recording Python bites every week because I do it with Michael but I’m not recording Test And Code all the time so I’m trying to hit up as many friends as I can to do this with me, to try to get me on to do it more and Anthony is one of the people that have agreed to come on the show more frequently and I really appreciate it.

Yeah. Thanks. Happy to be here.

That’s a good place to stop. Thanks for talking to me today.

Sure.

Thanks, Brian. That’s been really fun.