Replies: 7 comments
-
As much as I love AutoFixture, that is the one thing I dont like. The problem you are facing is that you lack the knowledge about what Build does. I think, when I started with AutoFixture I also wrote a lot of things like this. Your expectation is that your customization is additional. Basically you want to write code that says "create an IEntity instance with all properties generated automatically, but with Code having the value "0". The Build method sadly does not work like this. With your setup you told AutoFixture how to generate IEntity instances via NSubstitute. Build starts from scratch. So when you use build, it does not matter if you have setup the customization or not and plain vanilla AutoFixture does not know how to create interfaces. You have to write your code like this, if you want to use Build:
Or you could just use the Create method and overwrite the properties, you want to have fixed values for. Of course AutoFixture is a very open system. There are some advanced ways to achieve what you want, but the 2 approaches I described here are quick and easy to understand. |
Beta Was this translation helpful? Give feedback.
-
@bkqc even though the code snipped from @GeraldLx could work, the scenario you're describing was never supported by AutoFixture. As soon as you'll have property with only a getter and no setter the AutoFixture intentionally delegates the responsibility for creating mocks to mocking frameworks, since they have custom APIs to set up the instances which is too complex to build around and maintain. My suggestion is to create a fake implementation of the interface and use that to setup valid |
Beta Was this translation helpful? Give feedback.
-
Thanks for your inputs but finally, since the first proposition is incomplete from what I understand of @aivascu answer and the second one means maintaining this implementation, I ended up removing AutoFixture from the equation and instead simply use LinQ with NSubstitute:
I suppose the best solution, if it is possible, would be for AutoNSubstitute to implement a With that would do an assignment if it is R/W or a .Returns() if R/O but considering my very small use case, I won't dig deeper into the problem for now. |
Beta Was this translation helpful? Give feedback.
-
@GeraldLx , I don't have deep knowledge of AutoFixture but from what I saw in the source code, isn't your proposition identical, as far as the end result is concerned, to defining AutoNSubstituteCustomization of the fixture? How exactly is your proposed solution working? What does it do? |
Beta Was this translation helpful? Give feedback.
-
I tried to explain it in my initial post here, but I can try again ;) AutoFixture can create certain types out of the box, like strings etc. When you request a type from AutoFixture, AutoFixture checks internally which part of the configuration can create the type. So when you add the AutoNSubstitute configuration, you basically extend the AutoFixture configuration to make the creation of abstract classes and interfaces possible. So with the customization in place, you can successfully run this code:
This gives a fully created entity with all members set. What you tried to achieve was building an object with AutoFixture. When you do this, you do not use any customizations. You start from scratch generating a new object. Therefore with or without the customization AutoFixture has no clue how to build an IEntity instance. You can add the creation logic by using the FromFactory method. This method has a few overloads. So the simplest approach for your problem could be:
Another overload takes a specimen builder instance. So instead of calling Substitute.For myself, my code used the component from the customization library. In simple cases both code snippets lead to the same result. But as @aivascu already said, the simple solution only works for properties with setters. The SubstituteRelay also gives random values to readonly properties. The same goes for the With statement. You cannot use it for readonly properties, cause sadly this is hard coded in AutoFixture. There is no way to tell AutoFixture "hey, I have a customization that can do that". So unless you dont want to go very deep into AutoFixture and dont have the need to make your tests free of NSubstitute referenes, I would advice to write your tests more like this:
or
for readonly properties. Then you can use the customization and let AutoFixture create the substitutes. Any unwanted randomization you just overwrite. |
Beta Was this translation helpful? Give feedback.
-
Wow, thanks @GeraldLx! This is an awesome explanation. Thank you so much! Something like this should go into the official documentation to help understand the Build behaviour! However, I don't understand the part where you say that using your last snippets would prevent from having NSubstitute references in my tests. AutoNSubstitute needs a reference to NSubstitute (though it is not shown if using PackageReference but I would also not have control on the version used) and |
Beta Was this translation helpful? Give feedback.
-
Sorry for the late reply, but I was in vacation ;) Some guys like to reduce the dependencies as much as possible. So in theory you could stick with the in build AutoFixture options by passing in the ISpecimenBuilder instance to your tests. So in the case of NSubstitute it would be only the SubstituteRelay. That would make your tests open to using other mocking frameworks in the future. Personally I would not go this route. It feels a little bit like old days, when everyone wanted to be database agnostic to have the option to change the database, which 99,9 percent never did. The reason was mainly due to the fact you started this whole Build / With construct making things a little more complicated, but independent of NSubstitute. As said, I use the practical version with the Create and then Returns, but if you dont like it, there are ways to avoid this. |
Beta Was this translation helpful? Give feedback.
-
I'm trying to create a mock object using AutoNSubstitute but I keep getting the following error:
The stripped down code I use that crashes is
The target is
I also tried these that do work with the last 2 having their properties correctly filled by AutoFixture
Stack of the exception
I have also opened a question on StackOverflow with the exact same detail, just in case.
Beta Was this translation helpful? Give feedback.
All reactions