Serg046 / AutoFake

Mock any type members including static and non-virtual ones
MIT License
51 stars 4 forks source link

EntryPointNotFoundException when replacing an instance method call #267

Closed hanshsieh closed 1 year ago

hanshsieh commented 1 year ago

Let's say I have test code like below:

using AutoFake;

namespace Test3
{
    public class Order
    {
        public IList<LineItem> Items { get; }
        public Order()
        {
            Items = new List<LineItem>();
        }
    }
    public class LineItem
    {}
    public class OrderService
    {
        public string CreateOrder(Order order)
        {
            return "100";
        }
    }

    public class RequestHandler
    {
        private OrderService _orderService = new OrderService();
        public string HandleRequest()
        {
            Order order = new Order();
            order.Items.Add(new LineItem());
            return _orderService.CreateOrder(order);
        }
    }

    public class Tests
    {
        [Test]
        public void TestHandleRequest()
        {
            var fake = new Fake<RequestHandler>();

            var sut = fake.Rewrite(f => f.HandleRequest());
            sut.Replace((OrderService orderService) => orderService.CreateOrder(Arg.IsAny<Order>())).Return("1000");
            sut.Execute();
        }
    }
}

I use Replace to replace an instance method call, but I get the exception below

Message: 
System.EntryPointNotFoundException : Entry point was not found.

  Stack Trace: 
ExpressionExecutorImpl.Execute()
ExpressionExecutor`1.Execute()
FuncMockConfiguration`2.Execute()
Tests.TestHandleRequest() line 43

If I either remove the line order.Items.Add(new LineItem()) or sut.Replace(...), the test can run successfully. Did I make anything wrong?

Serg046 commented 1 year ago

This is one of the most complex concepts in the lib. In short, the thing is that LineItem class from your test's assembly and Fake's assembly are different that's why there is a need to replace all the references so that you can pass LineItem instance created in tests to the fake's instance. This time the issue is that there is no direct reference to LineItem, it is a generic parameter of List<LineItem>. The lib currenty just checks that List<...> is not part of Fake's assembly and thinks that there is no any reference to replace which is wrong. I found the wrong place and fixed the issue locally. Just need some time to make a better change and then release it.

The second thing is that the exception does not explain anything. I do want to improve it so that the user has a better understanding of what happens (will be done here https://github.com/Serg046/AutoFake/issues/153).

hanshsieh commented 1 year ago

I see. Thanks a lot.

Serg046 commented 1 year ago

I actually implemented a big change for that but that was not ideal so that I wanted to work on that a bit more. But then I ran into a situation when I had no free time... Now I am moving back and see that .NET team is bringing a new feature that will make AutoFake prod-like quality. The feature is Interceptors. My current idea is to freeze the current implementation and focus on this new feature to release AutoFake 1.* based on that. The current issue will be fixed by that automatically.

hanshsieh commented 1 year ago

That sounds like a great idea. Thank you.