On .NET Live - Imposter: A Mocking Library
dotnet
0:01 [music] [music] [music] [music] [music] [music] [music] [music] [music]
1:31 [music] [music] [music] [music] [music] [music] [music] [music] [music]
3:36 All right.
3:38 [laughter] I like the music on that promo.
3:39 Like, no.
3:41 We need to talk to the producers.
3:45 [laughter] Good morning, good evening, good afternoon, everyone.
3:47 Welcome to the show.
3:48 Welcome to 60 minutes or less.
3:52 I will see how long it's the show today of unscripted dotnet entertainment.
3:56 Our mission is to empower the dotnet community to achieve more.
4:00 My name is Maria Wenzel.
4:02 I'm now enjoyed by my co-host Katie Savage and Kim Soper.
4:06 Hello.
4:07 And I'd like to welcome today's guest Bichiko Chalidze,
4:11 if I didn't butcher your name.
4:14 Um, and you're going to be here talking about Imposter uh a mocking library.
4:19 I think our show title um is not correct.
4:22 We'll fix it after after the fact.
4:24 Uh but how about you introduce yourself, Bichiko?
4:28 Sure.
4:29 Thank you.
4:30 Uh I'm Bichiko Chalidze.
4:31 I'm a software architect and hands-on engineer.
4:34 Currently working at Method and uh I've been
4:37 a dotnet engineer for the past 10 years.
4:42 It's lovely to have you here.
4:44 Uh welcome to the show.
4:46 Uh so, how about we start your presentation?
4:50 Sounds good.
4:51 Uh yeah, so uh let me share my screen.
4:55 All right.
4:56 Uh today um I'll talk about Imposter.
5:00 Uh this is the mocking library.
5:02 Um and there are several alternatives also, right?
5:04 So, the first question maybe that comes to someone's mind is
5:08 why why another mocking library because we we have so many, right?
5:12 And there are a few reasons for that we're going to go into details as we go.
5:17 Uh but the primary motivation uh for this was the performance, right?
5:22 Uh the existing mocking libraries, which are Moq,
5:26 the probably the most popular, and Substitute, and FakeItEasy,
5:30 the way they work is that they use um runtime proxy generation,
5:36 which is basically my reflection emit.
5:39 Uh so, they generate classes at runtime.
5:42 So, when you want to, let's say, mock you a method, right?
5:45 It uh generates a runtime proxy uh in the runtime and then
5:50 it injects whatever uh code it wants in into it, right?
5:54 And this is uh a very useful method, right?
5:58 Proxy generation in general.
6:00 One downside with it um is the performance, right?
6:06 So, uh that was a primary motivation why I created Imposter.
6:10 And um I don't see an Imposter as a everyday mocking library,
6:14 meaning that of course you can use it in a small projects,
6:17 but where you really going to see a benefit is
6:20 when you have a large really large amount of tests, right?
6:24 Which are heavily using mocks.
6:26 Then uh there you may be able to shave minutes
6:29 from your um um build pipeline that where you're running tests, right?
6:35 So, that was a primary motivation.
6:37 Although um Imposter can be used as a everyday tool like a for a small projects.
6:43 There is um nothing that's going to stop you from doing that.
6:46 You might not see as many benefits
6:48 as in the scenarios that I was uh referring to, right?
6:53 And um maybe I go and I have prepared some code examples that uh
7:00 maybe help us they're going to help us understand how it actually works, right?
7:06 Uh I mentioned that uh performance was a primary motivation.
7:10 Although there Imposter is not the first
7:13 mocking library that's using a source generators, right?
7:16 There is another one which in fact is faster.
7:20 But the problem is that one is ergonomics.
7:23 The API is different.
7:27 And uh in my opinion it is quite unintuitive.
7:31 So, there is some learning curve and getting used
7:34 to it if you decided to go with that library, right?
7:38 And um one of the also design goals that I
7:42 had with Imposter was it to make it um seamless, right?
7:45 Make it easy to read.
7:46 And uh people and most of the developers
7:50 already are working with Moq and then Substitute, right?
7:53 So, instead of reinventing a new way of doing mocking,
7:57 I borrowed some of the ideas from those libraries.
8:00 And hence it's going to be easier for developers
8:03 to switch if they decided to do so, right?
8:08 So, the first thing uh that we need to do after installing the uh NuGet
8:11 package is that we go we uh instruct
8:16 the Imposter to generate the Imposter for us.
8:18 And it is an assembly level attribute that's most uh convenient.
8:22 Of course, it can be non-assembly level, of course, also, right?
8:26 So, here we just say that, okay, we have this ICalculator,
8:29 which is very simple class just as a tool some method with it, right?
8:34 And during the build it's just going to go and generate the Imposter, right?
8:38 So, the first thing first interaction is we need to create an Imposter, right?
8:42 So, Imposter is the main entry point for us
8:46 where we're going to define all the setup methods,
8:48 all the mocks on methods and properties and all that, right?
8:52 And the way you do it is you take the target type,
8:56 in this case calculator, and you do dot Imposter, right?
8:59 So, I think it's pretty nice.
9:01 I don't have to create, let's say,
9:02 new Moq and pass a generic parameter all that.
9:05 This reads much nicer in my mind.
9:09 And the second is, let's say, you want to mock the method, right?
9:13 Uh with Moq you have to do a setup and uh pass the um lambda in it,
9:20 which is not a terrible way.
9:21 It's it's okay, but um in my mind it's much nicer and reads much
9:26 uh straightforward when you have Imposter and dot
9:29 and you have all the methods available, which in this case is just sum, right?
9:34 And then you have uh parameters, right?
9:37 And here we have all the flexibilities
9:39 that we have with other uh mocking libraries.
9:41 Like, in this case we just say any,
9:43 but you can extend it and say is, for example, and pass the lambda here, right?
9:50 Let's say you want just the even numbers, right?
9:53 Uh then you can you can do that, right?
9:56 But um in this case, we're just going to go with any because
10:01 otherwise this test is going to fail, right?
10:03 And then you say returns five.
10:06 Okay, so this says that, well, as you might guess, for the any parameters,
10:11 if there's no more specific uh no more specific setup, just return five.
10:18 The second thing is uh sequential uh setup
10:21 and uh Mock Yu also has a support for that.
10:25 Right?
10:25 You you do a setup sequence.
10:28 Uh but here, I think it's again the um API is more ergonomic
10:34 in the sense that once you set up it for, let's say, one and one, right?
10:37 Here, we're just passing the direct values.
10:39 You can use the arc, but if you know the exact values, you can also do that.
10:44 Then you say returns, and then you call the then method,
10:47 and you set up the second callback, right?
10:49 Second What What happens when you call it the second time?
10:52 And then you do what happens when you call it the third time, right?
10:56 So, uh it looks nice.
10:59 And uh at the at the moment where you
11:01 want to uh you're you're done with setting up,
11:04 and now you want an instance, well, you call an instance, right?
11:07 And it gives you the um I calculator instance,
11:12 which is created uh the class itself generated at the compile time, right?
11:16 And here, it just demonstrates that whatever we did above indeed works.
11:21 So, here when we call the sum method the third time,
11:25 it indeed throws invalid operation exception as we requested it to do so.
11:30 And uh uh last part for the basic usage part is the uh verification, right?
11:36 Because with mocks, uh we don't we don't not only want to set up,
11:40 we also want to verify that those setups were called, right?
11:44 And here, you can do same thing, imposter.sum,
11:47 the same entry point as you have for the for the setting up,
11:51 you have for the verification.
11:54 But, with the verification, you have the called method,
11:56 which uh checks that it was called a specific amount of time, in this case,
12:01 once, although you can have a like pass an exact number,
12:05 or if you want to say at least once, or at most once.
12:08 Those uh tiny utility methods are also provided
12:12 just to increase uh readability a bit more.
12:15 All right, and then we do the same here
12:17 for the speci- specific parameter of one and one, right?
12:22 So, Hey, can I jump in with a real quick question?
12:24 Uh yeah, sure.
12:25 So, the the the dot imposter up on line 13, that's that's an extension method.
12:31 Does that just apply to like I can I can I can tack that on to any object?
12:38 Uh dot imposter?
12:39 No, it will be generated specifically for them uh objects.
12:44 So, it's not it's not like an in substitute,
12:47 where you have extension methods that you can
12:48 can call on uh objects that are not mocked,
12:52 but here, uh generated um imposter gets its own extension method.
12:57 Ah, okay, makes sense.
12:59 Great.
13:00 Carry on.
13:01 Uh great.
13:02 And this is the uh basic usage, right?
13:04 So, um just to uh cover um imposter
13:08 does have um ability to mock not only methods,
13:13 but also properties, indexers, and events, right?
13:16 And when I open up the documentation, there we're going to see all that.
13:20 Right?
13:21 Uh also, uh apart from the performance and the API ergonomics,
13:27 there is one more advantage, uh which is the uh strongly typed callbacks, right?
13:33 Uh just to reiterate what we said
13:35 with the Mock Yu and other uh mocking libraries,
13:38 since they generate those types at runtime, right?
13:43 They don't have the ability naturally
13:45 to provide us the strongly typed callbacks, right?
13:48 Because the type, for example, here we have mock, right?
13:52 And it does have the sum method,
13:53 but it cannot give you at compile time the signature of this method, right?
13:57 So, for example, what can happen is that the sum method,
14:01 which accepts two integer parameters,
14:06 it can have a returns with the value factory, which accepts strings, right?
14:11 Or you can have a callback, which accepts strings, and it's going to build,
14:15 but in the runtime, you're going to get an exception, right?
14:18 And uh this uh becomes just one more thing that you
14:22 need to worry about when you are refactoring methods, right?
14:25 Let's say you add a new parameter or change a type,
14:28 then you have to need to come here.
14:30 And also, just number of parameters are also not validated, right?
14:34 You can have a one parameter or 90,
14:36 and it won't be able to uh give you help you in the compile time, right?
14:41 But, with imposter, since everything is generated
14:45 at the compilation time, we do have that.
14:48 So, if you try here to, let's say, remove this parameter,
14:51 you're going to get a compilation error,
14:53 and same goes for any signature mismatch.
14:56 Right?
14:56 So, and this goes for the returns and the callbacks as well.
15:00 So, that's uh one more um uh advantage that you get.
15:04 So, before I go to the documentation side
15:08 and briefly briefly review that, maybe if there's any question,
15:11 I'm going to take a small pause.
15:17 If there are not, then I'm going to keep um Yeah,
15:21 I think you can you can continue.
15:23 There's no no questions on the chat yet.
15:25 Okay, sounds good.
15:27 All right, then.
15:28 Uh yeah, so the uh name of the um library is imposter.
15:34 So, you can uh Google it,
15:35 or I think uh link probably going to be in the description also.
15:39 So, here,
15:43 [gasps] um Okay, yeah.
15:45 Here, what you can see is the uh Penfold's benchmarks, right?
15:50 Uh so, as you can see, uh time-wise,
15:53 and this is done on a simple simple uh I calculator, right?
15:57 In this case, it's called square, but the same.
16:00 And here's the number of iterations,
16:01 like how many times did we access this method on the mocked object.
16:05 And for the one times, as you can see,
16:08 compared to uh Mock Yu and uh NSubstitute and FakeItEasy,
16:13 it's 10-fold faster than, if not more.
16:16 It's just for the one method, right?
16:18 And then when you go to 10 and 100, numbers change, but usually,
16:22 you should expect five to 10 times uh the uh
16:27 performance increase when it comes to the uh time, right?
16:31 Memory allocation is not that important.
16:33 Also, in some scenarios, it can be, and here we also have some good numbers.
16:38 Right?
16:39 Uh as far as the documentation goes, if you scroll down,
16:42 then you can find the links here to documentation.
16:45 All of those goes to docs, as does this one.
16:49 And here, what you can see is what I was mentioning.
16:52 I'm not sure what my screen is like wobbling, but okay.
16:55 Now, it's stable.
16:56 Yeah, so on the documentation page,
16:58 you can see that um we have the ability to um mock the methods,
17:05 method impersonation.
17:06 Um yeah, forgot to mention that uh imposter is
17:10 not restricted to uh impersonate or mock uh just interfaces.
17:15 It can do it for the classes as long as the methods are methods are virtual.
17:21 Right?
17:21 And it can do it for the properties as well,
17:24 and here you can see all the details how to actually do that.
17:29 Um same goes for any indexer and any anti-impersonation, right?
17:34 And uh one more thing that I want to mention is the implicit and explicit mode.
17:39 This idea was also borrowed from the Mock Yu.
17:42 And basically, the idea is that uh if you decide to go with an explicit mode,
17:48 then any method or a property that is accessed on the imposter,
17:53 and there is no explicit this is set up for that, it's going to throw.
17:57 While, if you have an uh in the implicit mode,
18:00 then it's just going to return the uh default value,
18:04 or just not going to do anything if it's like a void method.
18:08 Right?
18:09 And um there's also ability to call the uh base method.
18:12 I'm not going to go into to uh details like how to actually do it.
18:16 I guess I want to uh show that there is features covered,
18:20 so it's not like just some prototype that works on the simple mock method,
18:25 but it's it's um it has a lot
18:27 of features that you expect from the mocking library.
18:30 Okay?
18:31 And now, back to the uh repository.
18:35 Uh one thing I want to mention is that uh
18:38 is this screen wobbling happening on my machine also, or it's how you guys see?
18:44 I don't see it.
18:45 For us, everything's normal.
18:47 Yeah.
18:48 Okay.
18:48 There's no blinking breath.
18:51 [laughter] Yeah, it goes like uh shuffling the entire screen.
18:54 But, okay, cool.
18:55 Yeah, so uh what I want to mention, two things here, right?
18:58 It's an MIT license, so you can take it and do whatever you want.
19:02 Uh and another thing is that um it's still in its early days.
19:07 Um I released it, if I'm not mistaken, in uh January.
19:12 And there have been some issues and bugs,
19:14 and there is definitely room for improvement
19:17 as far as performance goes and code generation.
19:19 So, maybe you are someone who is looking
19:23 to for a contribution and project to find.
19:26 And it's very difficult to contribute
19:28 to a project that's out there for decades, right?
19:31 Usually, it's very very optimized, and it's really hard,
19:35 and it has a like big learning curve.
19:37 But, it's not the case for imposter.
19:39 So, it Maybe if you're looking for something,
19:41 you are more than welcome to contribute,
19:44 find issues, um refactor, uh make it better.
19:50 Right?
19:51 So, that is uh all I wanted to share.
19:54 I'm open for the questions, if there any.
20:00 So, um I think my my my curiosity uh for you is in terms of like what
20:07 inspired you to create this project uh and kind
20:11 of you mentioned that performance was one thing.
20:13 So, is that what was lacking in the other projects that were
20:18 out there or is there something else that prompted you to Yeah,
20:23 uh so uh first one was the the performance.
20:26 So, the um projects uh I mentioned not to go into too much details,
20:31 but we had a uh this uh room for improvement.
20:35 I mean that project where we have a lot of a lot of unit tests, right?
20:39 So, that was one motivation.
20:40 Another one was that uh mocking uh
20:44 source generators are pretty awesome technology, right?
20:47 And I thought there should be a a good mocking library that has
20:53 a good uh API ergonomics that's using the source generator because honestly,
20:57 when I first time heard about the source generation,
21:00 first things that came to my mind was was mocks, right?
21:03 Cuz that's that's kind of uh like so
21:06 common use of uh creating objects dynamically, right?
21:11 And the mocking them.
21:12 So, that was that were uh two uh motivations and yeah.
21:19 All right.
21:20 Cool.
21:22 And we have a question uh not related
21:24 to this content uh if we have content for SignalR.
21:27 So, keep an eye on on the shows.
21:30 Uh we we welcome everybody's shows in terms of people that are interested.
21:35 So, like if you're an expert SignalR, submit a show for SignalR.
21:39 Um yeah, uh I think like the show goal is to have a space for folks
21:46 to come and present like like Pichiko came
21:49 here first timer on the show presenting his project.
21:53 Uh and so, yeah, we we love we love seeing uh
21:58 new folks here come and share their their their passion projects, too.
22:04 [snorts]
22:04 Yeah, I I love this [clears throat] uh I I I I love this project, Pichiko.
22:08 I'm uh so, does it work like as expected just like like
22:12 just out of the box with the test runner in Visual Studio?
22:16 Yeah, [laughter]
22:17 yeah, so here uh um with a Visual Studio uh test explorer, you can run it.
22:25 The uh test itself uh in the project is using an XUnit,
22:29 but uh or you can I also test it in a ReSharper test runner.
22:33 So, there is no limitation in that in that sense.
22:37 Okay, great.
22:39 We do have a an audience question that just came up in the chat.
22:44 Uh so, somebody is asking, "How is this project different from Rocks,
22:49 which is another mocking library?" Yeah,
22:52 uh sure uh that was the one that I mentioned.
22:56 The uh difference is really in the API.
22:58 I took a look at the Rocks before I started
23:01 working on this one and uh it's my personal opinion,
23:06 but it really has reinvented the way you do the mocking.
23:09 So, the code doesn't read that well in my mind.
23:15 Um so, one of the focus with this one was to take the same idea,
23:20 but improve the readability.
23:21 So, that developers who are mostly working with Moq and have this knowledge
23:28 of how mocking works can transfer their knowledge
23:31 without uh without a huge learning curve.
23:36 Not a huge, but learning curve.
23:41 Can you uh can can you show us Here, let me put this back up.
23:44 Yeah, okay.
23:44 That that demo test again.
23:46 Um yeah, I don't think I have any questions on that.
23:50 That's really that that's really uh readable.
23:53 Like I mean, to your point, the the code is like really uh uh like
23:58 I like it better than than uh XTest anyway.
24:02 Or XUnit.
24:03 It's very [clears throat] like seems very straightforward to use it, right?
24:07 Cuz it just gets what what's part of the interface there.
24:11 Yeah, and uh so, like um it it's uh it is similar to Moq in that sense,
24:16 but for example, here when you have return, right?
24:19 It only gives you what's available here.
24:21 So, for example, it doesn't give you returns.
24:24 It helps you guide what you can do.
24:26 From here, you can do a callback or do a then.
24:29 Or when you would do a then, from here, you can do a throw or returns.
24:33 And so, very composable.
24:36 Yeah.
24:38 So, it's uh yeah, it tries to lead you and to save
24:43 you from the run time errors as much as possible.
24:47 Yeah.
24:48 How how many iterations have you gone through
24:51 to get to this point in the project?
24:52 Like how long have you been working on it?
24:54 It seems like readability is a very difficult issue to tackle.
24:59 Yeah, uh a lot actually.
25:01 I think I started working on uh early June last year
25:06 and project was over uh somewhere in the end of December.
25:10 And um yeah, the initial version, I think it uh the Git history has it,
25:17 but initial version was much much difficult.
25:20 Right?
25:21 And and as I progressed,
25:22 um then there are some nuances that doesn't necessarily appear.
25:27 So, for example, this sum method right here, it's super simple case, right?
25:31 You can probably code up something that does
25:35 just simple method mocking in a day, but once you take into account all
25:40 different kind of parameters like out parameter,
25:43 ref parameter, params, or if method uh it is returning task, right?
25:49 These need to get to details, then it tries to um how to say?
25:55 I think it becomes more work to keep the API level smooth and hide all
26:01 this complexity and behind the scenes what needs
26:04 to be behind the scenes uh hidden, right?
26:07 So, uh there was definitely uh some uh work in this area.
26:13 Um the iteration, I don't remember exactly,
26:16 but uh especially for the mocking methods,
26:19 I think those we are the uh ones that I
26:21 spent uh most of the time on the mocking methods
26:25 could probably take an uh maybe couple of months at least
26:29 to have the first version that looks like something usable.
26:34 So, what's what's next?
26:35 What what do you want to add to the project now?
26:39 Yeah, uh so, and now there are some uh
26:42 improvements in the performance like the code generator itself.
26:45 Um I did not get time to go back and optimize
26:49 and there is a room for uh room for improvement in that.
26:54 And the second thing that's kind of probably be a long
26:57 term is um I'm exploring the idea of IL waving.
27:01 If there's a way that Imposter can do a IL rewrite and that's going
27:08 to open up the room for mocking
27:10 with static methods or non-virtual methods, right?
27:14 Because right now there don't doesn't seem to be a single
27:17 uh library that gives you both of the both of the worlds.
27:21 So, in the long term, I'm trying to uh incorporate that as well.
27:26 So, that's when it comes to mocking, uh you have all you need.
27:31 Very cool.
27:32 I'm look forward to that.
27:34 Thank you.
27:41 You're you're muted, Myra.
27:45 I was double muted because I was choking with my coffee in the back.
27:51 [laughter] I got coffee in my mouth.
27:55 I apologize for that.
27:56 No, so um yeah, I know I I I
27:59 appreciate you coming on the show and showing your project.
28:03 Um and it's totally fine.
28:04 We can we can finish early.
28:07 Um yeah, and it's super interesting.
28:09 So, folks, go give it a try.
28:11 Go contribute to Pichiko's uh project.
28:14 Um if you're new to open source, uh like he said,
28:18 it's a good way to start uh by filing issues.
28:22 So, so go check it out.
28:24 Um and next week, uh we're going to have Steve Smith Steve
28:29 Ardalis Smith back to talk about AI offers benefits, but at what cost?
28:36 That seems that seems interesting.
28:39 Um so, we'll [laughter] We all know that there's pros and cons to everything.
28:49 Uh so, I want I want to thank everyone for watching on dotnet live.
28:54 Uh we you can go to dot.net/live to find previous shows.
29:01 We have a plethora of shows there.
29:03 And tune in next week.
29:05 We'll see you then.
29:07 Thank you.
29:10 [music]