FakeItEasy | The easy mocking library for .NET | Mock library
kandi X-RAY | FakeItEasy Summary
Support
Quality
Security
License
Reuse
Currently covering the most popular Java, JavaScript and Python libraries. See a Sample Here
FakeItEasy Key Features
FakeItEasy Examples and Code Snippets
Trending Discussions on FakeItEasy
Trending Discussions on FakeItEasy
QUESTION
I'm trying to fake a sealed external audio source using FakeItEasy.
I've wrapped the audio source and successfully faked the wrapper, so I know the basics are right. Here's the bit I'm currently stuck on:
The audio source returns isPlaying = true after it's been called with Play(). isPlaying will remain true until the audio clip has finished playing at which point it'll return to false.
I can fake the first part of this with the following code:
A.CallTo(() => fakeAudioSourceWrapper.Play())
.Invokes(() => fakeAudioSourceWrapper.isPlaying = true)
Which successfully fakes isPlaying being true after the Play function is called. What I'd like to do is then delay a certain time and then make it return false to simulate what happens after the clip has finished playing.
I tried
A.CallTo(() => fakeAudioSourceWrapper.Play())
.Invokes(() => fakeAudioSourceWrapper.isPlaying = true)
.Then
.Invokes(() => fakeAudioSourceWrapper.isPlaying = false);
with the idea that a call to isPlaying would return true the first time it was called after Play() was called, and return false the second time, but got no joy.
Is there a way to do this?
ANSWER
Answered 2022-Mar-31 at 16:10Your solution would probably work if Play
were called more than once, since you're configuring what Play does (although I think you switched the true and false). I'm guessing from the question that Play
is only called once. In that case, you want Play to perform an action that will set up changing behaviour between calls to isPlaying.
Consider the approach in this passing test, where Play
causes isPlaying
to return true
exactly once (the default behaviour for an unconfigured bool-returning Fake's method is to return false
):
public interface IAudioSourceWrapper {
public bool isPlaying {get;set;}
public void Play();
}
[Fact]
public void PlayThenDoNotPlay()
{
var fakeAudioSourceWrapper = A.Fake();
A.CallTo(() => fakeAudioSourceWrapper.Play())
.Invokes(() => {
A.CallTo(() => fakeAudioSourceWrapper.isPlaying).Returns(true).Once();
});
fakeAudioSourceWrapper.isPlaying.Should().Be(false);
fakeAudioSourceWrapper.Play();
fakeAudioSourceWrapper.isPlaying.Should().Be(true);
fakeAudioSourceWrapper.isPlaying.Should().Be(false);
}
QUESTION
When attempting to supply a fake delegate for a method with an optional parameter in a faked object
type MyType () =
abstract B: ?s:string -> unit
default x.B (?s: string) = Option.iter (printfn "Implemented: %s") s
[]
let doit () =
let a = A.Fake()
A.CallTo(fun () -> a.B(ignored())).Invokes(fun s -> Option.iter (printfn "Faked: %s") s)
a.B "Hello"
FakeItEasy complains
FakeItEasy.Configuration.FakeConfigurationException: Argument constraint is of type System.String, but parameter is of type Microsoft.FSharp.Core.FSharpOption`1[System.String]. No call can match this constraint.
Is there a way to make this run without changing the type definition ?
ANSWER
Answered 2022-Mar-23 at 05:36OK, I was able to reproduce your error message by defining ignored
as:
let ignored<'t> () = A<'t>.Ignored
The problem is that you've defined a string constraint for an argument that's actually a string option. You can work around this by explicitly naming the parameter ?s
when you call the member, like this:
A.CallTo(fun () -> a.B(?s=ignored())).Invokes(fun s -> Option.iter (printfn "Faked: %s") s)
Now the constraint has the correct type, Option
, and the code executes without error. Output is:
Faked: Hello
This SO answer has more details about specifying values for optional arguments.
QUESTION
Using version 7.3.0 of FakeItEasy. In following code I am getting message that call to method GetById is not configured, yet I am configuring it. What I am doing wrong? There is no overload for the GetById method.
var fakeConnection = A.Fake();
var fakeResolver = A.Fake();
var logger = A.Fake>();
var repository = new DummyAggregateRepository(fakeConnection, fakeResolver, logger);
var fakeRepository = A.Fake(
o =>
{
o.Wrapping(repository);
o.Strict();
});
var aggregateId = Guid.NewGuid();
A.CallTo(() => fakeRepository.GetById(aggregateId, A._))
.CallsWrappedMethod();
var fixture = new AutoFixture.Fixture();
var events1 = fixture.CreateMany(10).Cast();
var events2 = fixture.CreateMany(10).Cast();
var events = events1.Union(events2).ToList();
A.CallTo(
() => fakeRepository.GetEvents(
"dummyAggregate-" + aggregateId.ToString("N"),
aggregateId.ToString(),
A._))
.Returns(events);
var aggregate = await fakeRepository.GetById(aggregateId, default);
GetById implementation is virtual method
public virtual async Task GetById(Guid aggregateId, CancellationToken ct)
{
ct.ThrowIfCancellationRequested();
var streamName = this.GetStreamName(aggregateId);
using var scope = EventStoreCommon.CreateScope(Tracer.Instance, nameof(this.GetById), streamName);
var events = await this.GetEvents(streamName, aggregateId.ToString(), ct);
if (events.Any() == false)
{
throw new AggregateNotFoundException(aggregateId, typeof(TAggregate));
}
var aggregate = new TAggregate();
foreach (var @event in events)
{
aggregate.ApplyEvent(@event);
}
return aggregate;
}
Error reported
FakeItEasy.ExpectationException: Call to unconfigured method of strict fake: MyCompany.EventStore.Test.AggregateRepositoryTests.DummyAggregateRepository...
FakeItEasy.ExpectationException
Call to unconfigured method of strict fake: MyCompany.EventStore.Test.AggregateRepositoryTests.DummyAggregateRepository.GetById(aggregateId: d8d0445d-7f82-4636-82fc-2e8f14be7f3d, ct: System.Threading.CancellationToken).
at FakeItEasy.Core.StrictFakeRule.Apply(IInterceptedFakeObjectCall fakeObjectCall) in C:\projects\fakeiteasy\src\FakeItEasy\Core\StrictFakeRule.cs:line 53
at FakeItEasy.Core.FakeManager.ApplyBestRule(IInterceptedFakeObjectCall fakeObjectCall) in C:\projects\fakeiteasy\src\FakeItEasy\Core\FakeManager.cs:line 276
at FakeItEasy.Core.FakeManager.FakeItEasy.Core.IFakeCallProcessor.Process(InterceptedFakeObjectCall fakeObjectCall) in C:\projects\fakeiteasy\src\FakeItEasy\Core\FakeManager.cs:line 178
at FakeItEasy.Creation.CastleDynamicProxy.CastleDynamicProxyGenerator.ProxyInterceptor.Intercept(IInvocation invocation) in C:\projects\fakeiteasy\src\FakeItEasy\Creation\CastleDynamicProxy\CastleDynamicProxyGenerator.cs:line 187
at Castle.DynamicProxy.AbstractInvocation.Proceed()
at Castle.Proxies.DummyAggregateRepositoryProxy.GetById(Guid aggregateId, CancellationToken ct)
at MyCompany.EventStore.Test.AggregateRepositoryTests.GetByIdTests.When_Stream_Exists_Should_Create_Instance_Of_Aggregate_With_Applied_Events() in C:\github\MyCompany_2\libraries\eventstore\test\MyCompany.EventStore.Test\AggregateRepositoryTests\GetByIdTests.cs:line 131
at System.Threading.Tasks.Task.<>c.b__139_0(Object state)
at Xunit.Sdk.AsyncTestSyncContext.<>c__DisplayClass7_0.b__1(Object _) in C:\Dev\xunit\xunit\src\xunit.execution\Sdk\AsyncTestSyncContext.cs:line 75
ANSWER
Answered 2022-Mar-08 at 19:19Updated after getting new code and stack trace. Original answer left below
I think it's a bug.
Boring explanation:
Strict
and Wrapping
each add rules to the front of the faked object's rules list. The rules apply to all incoming calls. The first rule found that matches a call is triggered. So in your configuration, Wrapping
is added making the Fake attempt to forward all calls to the wrapped object. Then Strict
, so now the Fake will reject all calls.
You'd then expect
A.CallTo(() => fakeRepository.GetById(aggregateId, A._))
.CallsWrappedMethod();
to add a rule that would cause an incoming matching GetById
call to be forwarded to the wrapped method, but the implementation of CallsWrappedMethod
appears to be missing a this.AddRuleIfNeeded()
call around line 127. (You can see that CallsBaseMethod
just above has this call.)
I've verified that no rule is added by the CallsWrappedMethod
configuration. Likely has been broken since implemented in FakeItEasy 6.0.0 (issue #1717).
I created issue #1870 which is now fixed and released as part of FakeItEasy 7.3.1.
Original response, which was wrong, but did ask for more info:
Likely because a call was made to an unconfigured method on a strict faked repository.
We can't see DummyAggregateRepository
, so there's going to be some speculation here. Based on the lack of errors earlier, I assume that GetById
is virtual or abstract, so your call should be passed to the wrapped instance.
Nothing jumps out at me as I read your question, but this sort of thing usually pops up when
- a call is made to a different fake object than expected, or
- a call is made to a different method than expected, usually because there's an overload and the wrong method was configured
- a call is made to the expected fake object method, but with unanticipated arguments
If you edit your question, supplying
- the FakeItEasy version you're using
- the definition of
DummyAggregateRepository
, and - the entire exception that's returned, including stack traces
we may be able to help better.
QUESTION
I have the following appsettings.json configuration.
"SettingsConfig": [
{
"Name": "Something",
"Node": "Something",
"SettingName": "Something"
},
{
"Name": "Something",
"Node": "Something",
"SettingName": "Something"
}]
I want to write UnitTest ,but the following syntax does not work.
_configuration = A.Fake();
A.CallTo(() => _configuration.GetSection("SettingsConfig")).Returns(new List());
Error message: IConfigurationSection does not contain definition for Returns.
How IConfiguration can be mocked with FakeItEasy syntax in order to apply mock data for UnitTesting?
ANSWER
Answered 2022-Jan-11 at 12:19First, you should implement method that reads from file, which exists in the projects of unit test. So, if there is no file .json that you can read from you won;t be able to GetSection at all. So add file there then apply:
private IConfiguration ApplyConfiguration()
{
var configurationBuilder = new ConfigurationBuilder();
configurationBuilder.AddJsonFile("settingsConfig.json");
var config = configurationBuilder.Build();
config.GetSection("settingsConfig").Get>();
return config;
}
Then in your business logic add:
var config = ApplyConfiguration();
You will see that config contains all the configuration there, so no need to call OnCall .Returns() at all.
QUESTION
I have this block of code that I would like to test
class SearchEngine
{
public void Search()
{
var module = new SearchModule();
module.Search();
}
}
I have simplified it but I cannot provide a searchmodule instance as a parameter of the function Search
, nor as a constructor parameter of the class SearchEngine
.
Is there a way to insure that the module
object will be a fakeiteasy fake when I write my unit test?
I would like to be able to do some CallTo
verifications to the module object, notably that module.Search()
was called when we call Search()
ANSWER
Answered 2022-Jan-21 at 21:14Is there a way to insure that the module object will be a fakeiteasy fake when I write my unit test?
No, it's not possible, at least not with the current shape of your code. FakeItEasy can't intercept instance creation using new
.
If you want to fake something, it has to be provided somehow to the system under test. The SUT can't create it itself.
I cannot provide a searchmodule instance as a parameter of the function
Search
, nor as a constructor parameter of the classSearchEngine
Could you inject a factory instead? Something like this:
public interface ISearchModuleFactory
{
SearchModule Create();
}
class SearchEngine
{
private readonly ISearchModuleFactory _searchModuleFactory;
public SearchEngine(ISearchModuleFactory searchModuleFactory)
{
_searchModuleFactory = searchModuleFactory;
}
public void Search()
{
var module = _searchModuleFactory.Create();
module.Search();
}
}
You could then test SearchEngine like this:
// Arrange
var factory = A.Fake();
var module = A.Fake();
A.CallTo(() => factory.Create()).Returns(module);
var searchEngine = new SearchEngine(factory);
// Act
searchEngine.Search();
// Assert
A.CallTo(() => module.Search()).MustHaveHappened();
QUESTION
I have looked quite a lot on the internet but somehow I am not grasping the concept to solve my problem. It should not be that complicated.
I have a SUT (System Under Test), which has an event action like:
event Action DownloadFinished;
Now i want to raise this event using the fake object (using fakeiteasy), like:
fakeObject.DownloadFinished = Raise.With();
but the above line shows error as it says "Raise cannot take 3 arguments". Could someone recommend how to solve this issue.
ANSWER
Answered 2021-Sep-20 at 13:46According to my reading of the docs, if you're using a non-EventHandler
event, you need to use Raise.FreeForm.With
:
fakeObject.DownloadFinished += Raise.FreeForm.With(implementerOfSomeInterface, false, string.Empty);
or similar
QUESTION
I'm trying to create a method that would allow a "method group" to be passed in. Basically this is for testing where I want to make sure that a method was called. FakeItEasy already allows for the following code
public static IAnyCallConfigurationWithReturnTypeSpecified ReturnForMethod(
this Fake fake,
string methodName, ReturnType returnObj)
{
var call = fake.AnyCall().WithReturnType().Where(s => s.Method.Name == methodName);
call.Returns(returnObj);
return call;
}
//Called using
new Fake().ReturnForMethod(nameof(IDummyFactory.Create), testStr);
For cleaner code I'd prefer to write something like
public static IAnyCallConfigurationWithReturnTypeSpecified ReturnForMethodF(
this Fake fake,
MethodGroup method, ReturnType returnObj)
Basically the same way nameof works. Using a function so I would want the method called as follows
new Fake().ReturnForMethod(s=> s.Create, testStr); --NoInvoke as just want method group
ANSWER
Answered 2021-Aug-10 at 10:04"Method group" is a concept that exists only in the language's syntax, there is no runtime type that corresponds to a method group.
Before I answer the question, you can just do this at callsite:
new Fake().ReturnForMethod(nameof(s.Create), testStr);
I don't see any reason s => s.Create
would be better or more readable than nameof(s.Create)
.
Now for the fun part. Method groups are convertible to compatible delegate types as governed by an impossibly complicated set of magic rules.
So we would be looking for a method with a signature of:
public static IAnyCallConfigurationWithReturnTypeSpecified ReturnForMethod(
this Fake fake,
Expression> methodGroupExpression,
TReturnType returnObject) where TSUT : class
where TDelegate : Delegate
We're working with Expression
s, so we will have to create an ExpressionVisitor
that traverses the Expression
tree and looks for method calls on the appropriate type. For simplicity we are going to assume that you are always calling the method with just a single x => x.Foo
expression. Assuming we have a visitor class that does this, the body of our method is straightforward:
public static IAnyCallConfigurationWithReturnTypeSpecified ReturnForMethod(
this Fake fake,
Expression> methodGroupExpression,
TReturnType returnObject) where TSUT : class
where TDelegate : Delegate
{
var visitor = new ExtractMethodNameExpressionVisitor();
var methodName = visitor.ExtractMethodName(methodGroupExpression);
if (methodName is null)
{
throw new InvalidOperationException();
}
var call = fake.AnyCall().WithReturnType().Where(s => s.Method.Name == methodName);
call.Returns(returnObject);
return call;
}
The expression s => s.Create
is enriched with some magical compiler generated code during compilation, which converts it to the appropriate delegate type. But the method group itself is nested somewhere in it as a ConstantExpression
of type MethodInfo
. Our visitor class will traverse the tree, find such an expression and save its name.
class ExtractMethodNameExpressionVisitor : ExpressionVisitor
{
private string? _methodName;
public string? ExtractMethodName(Expression expression)
{
_methodName = null;
this.Visit(expression);
return _methodName;
}
protected override Expression VisitConstant(ConstantExpression node)
{
if (node.Type == typeof(MethodInfo) &&
node.Value is MethodInfo methodInfo &&
methodInfo.DeclaringType == typeof(T))
{
_methodName = methodInfo.Name;
}
return base.VisitConstant(node);
}
}
And now we can test this:
var fake = new Fake();
fake.ReturnForMethod(s => s.Create, "testStr");
var result = fake.FakedObject.Create();
Console.WriteLine(result);
The unfortunate part is that this doesn't work. As of C#9 at least, delegate types are kind of a second-class citizen in the language, and generic type inference for them does not work. So the above ReturnForMethod
call does not compile, because the compiler cannot infer that a function returning string
and taking no arguments is actually Func
. So the callsite must look like this:
fake.ReturnForMethod, string>(s => s.Create, "testStr");
which makes this solution much less appealing. The good news is that, if I understand the proposals correctly, in C#10 (or maybe C#11 if the feature misses C#10's release window) this would work without the explicit type signature.
You can find the full working demo here.
QUESTION
I'm using AutoFixture in my unit tests. The SUT is using AutoMapper. During execution of the unit test, I noticed that IMapper (interface of AutoMapper) was getting mocked by AutoFixture and thus disregarding any mapping profiles I have in my code.
So I wrote a customization to be able to pass in an IMapper instance so that AutoFixture will not mock this interface. But now it looks like that AutoFixture won't mock any other interfaces as well. This used to work before I introduced the AutoMapper customization.
AutoFixture.ObjectCreationExceptionWithPath : AutoFixture was unable to create an instance from Microsoft.Extensions.Logging.ILogger`1[MyAPI.Controllers.CustomerController] because it's an interface. There's no single, most appropriate way to create an object implementing the interface, but you can help AutoFixture figure it out.
If you have a concrete class implementing the interface, you can map the interface to that class:
fixture.Customizations.Add(
new TypeRelay(
typeof(Microsoft.Extensions.Logging.ILogger`1[MyAPI.Controllers.CustomerController]),
typeof(YourConcreteImplementation)));
Alternatively, you can turn AutoFixture into an Auto-Mocking Container using your favourite dynamic mocking library, such as Moq, FakeItEasy, NSubstitute, and others. As an example, to use Moq, you can customize AutoFixture like this:
fixture.Customize(new AutoMoqCustomization());
See http://blog.ploeh.dk/2010/08/19/AutoFixtureasanauto-mockingcontainer for more details.
Here's what I have now. As can you see, I'm still using the AutoMoq customization as well. My AutoMapperDataAttribute is newing up the fixture so the AutoMoq customization will not be applied presumably. Is it possible to work with an existing Fixture instance rather than recreating it in my attribute? I could add the AutoMoq customization in AutoMapperDataAttribute as well, but it would be better to separate the AutoMoq and AutoMapper behavior.
Unit test:
[Theory, AutoMoqData, AutoMapperData(typeof(MappingProfile))]
public async Task GetCustomers_ShouldReturnCustomers_WhenGivenCustomers(
[Frozen] Mock mockMediator,
List customers,
[Greedy] CustomerController sut,
GetCustomersQuery query
)
{
//Arrange
var dto = new GetCustomersDto
{
TotalCustomers = customers.Count,
Customers = customers
};
mockMediator.Setup(x => x.Send(It.IsAny(), It.IsAny()))
.ReturnsAsync(dto);
//Act
var actionResult = await sut.GetCustomers(query);
//Assert
var okObjectResult = actionResult as OkObjectResult;
okObjectResult.Should().NotBeNull();
var response = okObjectResult.Value as Models.GetCustomers.GetCustomersResult;
response.TotalCustomers.Should().Be(customers.Count);
response.Customers.Count.Should().Be(customers.Count);
response.Customers[0].AccountNumber.Should().Be(customers[0].AccountNumber);
response.Customers[1].AccountNumber.Should().Be(customers[1].AccountNumber);
}
AutoMapper customization:
public class AutoMapperDataAttribute : AutoDataAttribute
{
public AutoMapperDataAttribute(Type type)
: base(() => new Fixture().Customize(new AutoMapperCustomization(CreateMapper(type))))
{
}
private static IMapper CreateMapper(Type profileType)
{
return new MapperConfiguration(opts =>
{
opts.AddProfile(profileType);
})
.CreateMapper();
}
}
public class AutoMapperCustomization : ICustomization
{
private readonly IMapper mapper;
public AutoMapperCustomization(IMapper mapper) => this.mapper = mapper;
public void Customize(IFixture fixture)
{
fixture.Inject(mapper);
}
}
ANSWER
Answered 2021-Jul-12 at 07:39AutoFixture can only build upon the testing framework only as much as it allows itself to be extended. In xUnit 2 each provided DataAttribute
is considered, a distinct provider of arguments for the test, which is why they are isolated during runtime.
The recommended option here is to create a data attribute that will apply both AutoMoq and the AutoMapper customization.
You can achieve this by using a CompositeCustomization
and then using it in a custom AutoDataAttribute
implementation.
public class AutoMappedDomainDataCustomization : CompositeCustomization
{
public AutoMappedDomainDataCustomization()
: base(
new AutoMoqCustomization(),
new AutoMapperCustomization(typeof(TestProfile)))
{
}
}
The separation of concerns, that you want to achieve, in AutoFixture, should come from having small composable and reusable customizations.
Another less known way to customize the fixture is via the parameter customization.
[AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false)]
public class CustomerMapperAttribute : Attribute, IParameterCustomizationSource
{
public ICustomization GetCustomization(ParameterInfo parameter)
{
// Your implementation here
}
}
This allows to customize the way specific parameters are created by the fixture.
[Theory, AutoMockData]
public void Foo([CustomerMapper][Frozen]IMapper mapper, MySut sut)
{
}
It just so happens that just recently I published a package AutoFixture.Community.AutoMapper
, that implements the AutoMapper integration. Perhaps you would find it useful or you'll want to copy some of its features. Here's the link to the respository .
QUESTION
I am new to FakeItEasy and I am having a problem asserting if an async method has been called. It fails assertion because it hasn't been called. I have done my best to ensure the assertion matches the configured call but still no dice.
[HttpPost]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status201Created)]
public async Task Post(CreateOwnerRequest requestModel)
{
var command = new CreateOwnerCommand { RequestModel = requestModel };
var ownerResponse = await _mediator.Send(command, default);
//TODO: return URI for the new resources
return Created("", ownerResponse);
}
[Theory]
[ClassData(typeof(ValidCreateOwnerTestData))]
public async void ShouldCallCreateOwnerHandler(CreateOwnerRequest validCreateOwnerModel)
{
// Arrange
var fakeMediator = A.Fake();
A.CallTo(() => fakeMediator.Send(new CreateOwnerCommand { RequestModel = validCreateOwnerModel },
default)).Returns(A.Dummy>());
var ownerController = new OwnerController(fakeMediator);
// Act
_ = await ownerController.Post(validCreateOwnerModel);
// Assert
A.CallTo(() => fakeMediator.Send(new CreateOwnerCommand { RequestModel = validCreateOwnerModel },
default)).MustHaveHappened();
}
public class ValidCreateOwnerTestData : IEnumerable
{
public IEnumerator GetEnumerator()
{
yield return new object[] { new CreateOwnerRequest { FirstName = "Foo", LastName = "Bar" } };
}
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}
ANSWER
Answered 2021-Jul-02 at 23:08In your assertion, you create a new instance of CreateOwnerRequest
. Obviously, this isn't the same instance that is actually used in the controller action, so it isn't considered equal, and the assertion fail.
You could override Equals
on CreateOwnerRequest
so that they are considered equal, but it's probably not a good idea, since you would do it only in order to satisfy the assertion.
A better approach is to use argument constraints to specify a condition that the argument must match:
// Assert
A.CallTo(() => fakeMediator.Send(
A.That.Matches(command => /* some condition here */))
A.Ignored))
.MustHaveHappened();
(note that I also changed default
to A.Ignored
, because you probably don't want the assertion to fail if the controller action starts using a real cancellation token...)
QUESTION
I'm new to FakeItEasy, sorry if the solution is obvious.
This is the simplified code which reproduces the problem:
I have a base class:
public abstract class BaseClass
{
public void Do()
{
Do_Override();
}
protected abstract void Do_Override();
}
and a derived one:
public class ImplementingClass: BaseClass
{
protected override void Do_Override()
{
ProtectedDo();
}
protected virtual void ProtectedDo()
{
}
}
In my test I want to see if ProtectedDo()
was called. I've tried to test in two ways, but tests are failing with the same message:
1st. In debug mode it is not entering in Do_Override()
public class ImplementingClassShould
{
[Fact]
public void Run_ProtectedDo()
{
var fake = A.Fake();
fake.Do();
A.CallTo(fake).Where(_ => _.Method.Name == "ProtectedDo").MustHaveHappened();
}
}
2nd. In debug mode it is entering in Do_Override()
public class ImplementingClassShould
{
[Fact]
public void Run_ProtectedDo_V2()
{
var sut = new ImplementingClass();
var sutFakeWrapper = A.Fake(_ => _.Wrapping(sut));
sutFakeWrapper.Do();
A.CallTo(sutFakeWrapper).Where(_ => _.Method.Name == "ProtectedDo").MustHaveHappened();
}
}
ANSWER
Answered 2021-Jun-30 at 12:33Your test is perfectly good, as far as it goes. If you run it, it'll tell you that ProtectedDo
was not called, which is accurate. Because Do_Override
is virtual, FakeItEasy intercepts the call. (The protectedness doesn't affect things in this case.)
If you don't want Do_Override
to be intercepted by FakeItEasy, you should configure the Fake to call the base method instead of handling the call itself:
[Fact]
public void Run_ProtectedDo()
{
var fake = A.Fake();
A.CallTo(fake).Where(_ => _.Method.Name == "Do_Override").CallsBaseMethod();
fake.Do();
A.CallTo(fake).Where(_ => _.Method.Name == "ProtectedDo").MustHaveHappened();
}
Update in light of the newly added Run_ProtectedDo_V2
test:
I expect you know this already, @fmm, but the test still fails. This is because when sutFakeWrapper.Do
is called, it forwards to the wrapped sut.Do
. Since sut
is a concrete ImplementingClass
, it calls its Do_Override
, which calls its ProtectedDo
, so its possible do debug into a ProtectedDo
method call. Only it's sut.ProtectedDo
, not sutFakeWrapper.ProtectedDo
. Hence the test failure.
Community Discussions, Code Snippets contain sources that include Stack Exchange Network
Vulnerabilities
No vulnerabilities reported
Install FakeItEasy
Support
Find, review, and download reusable Libraries, Code Snippets, Cloud APIs from over 650 million Knowledge Items
Find more librariesExplore Kits - Develop, implement, customize Projects, Custom Functions and Applications with kandi kits
Save this library and start creating your kit
Share this Page