On .NET Live - Imposter: A Mocking Library

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]

Study with Looplines Download Captions Watch on YouTube