简体   繁体   中英

Mocking IStringLocalizerFactory in C# throws NullReferenceException

I'm trying to write a test for a service that uses IStringLocalizerFactory to translate strings. All of the translations are in a single Resource file. I cannot seem to get the Mock for it to work, as it always throws a NullReferenceException. When debugging, it shows that _localizer is null. When I remove the localizer logic completely, the test succeeds.

Code I'm trying to test:

        private readonly IStringLocalizer _localizer;

        public EventService(IEventRepository eventRepository, IMemberEventRepository memberEventRepository, IStringLocalizerFactory factory)
        {

            this._eventRepository = eventRepository;
            this._memberEventRepository = memberEventRepository;
            this._localizer = factory.Create(typeof(Resource));
        }

        public async Task CreateEventRegistrationAsync(MemberEvent entity)
        {
            if (await this._memberEventRepository.GetMemberEvent(entity.EventId, entity.MemberId) != null)
            {
                throw new ArgumentException(_localizer["This member already participates in this event."].Value);
            }

            await this._memberEventRepository.CreateAsync(entity);
        }

My tests:

        private Mock<IStringLocalizerFactory> _stringLocalizerFactoryMock = new Mock<IStringLocalizerFactory>();

        public EventServiceTests()
        {
            _service = new EventService(_eventRepoMock.Object, _memberEventRepoMock.Object, _stringLocalizerFactoryMock.Object);
        }

        [Fact]
        public async Task CreateEventRegistrationAsync_ShouldThrowArgumentException_WhenMemberAlreadyRegisteredForEvent()
        {
            int eventId = 456;
            int memberId = 123;

            _stringLocalizerFactoryMock.Setup(x => x.Create(typeof(Resource)))
                .Returns(() => new StringLocalizer<Resource>(_stringLocalizerFactoryMock.Object));

            MemberEvent registration = new MemberEvent
            {
                EventId = eventId,
                MemberId = memberId
            };

            _memberEventRepoMock.Setup(x => x.GetMemberEvent(eventId, memberId))
                .ReturnsAsync(registration);
            
            await Assert.ThrowsAsync<ArgumentException>(async () => await _service.CreateEventRegistrationAsync(registration));
        }

From examining the subject under test I see that

_localizer["This member already participates in this event."].Value 

will throw a null exception because _localizer[...] was not setup and thus fail when .Value is invoked.

Consider mocking a IStringLocalizer<T> so that it can be setup to behave as expected when the test is invoked.

//...

var localizer = new Mock<IStringLocalizer<Resource>>();

localizer
    .Setup(_ => _[It.IsAny<string>()])
    .Returns(string key => new LocalizedString(key, key));

_stringLocalizerFactoryMock
    .Setup(_ => _.Create(It.IsAny<Type>()))
    .Returns(() => localizer.Object));

//...

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM