Starts in:
2 DAYS
5 HRS
16 MIN
20 SEC
Starts in:
2 D
5 H
16 M
20 S
Open Closed

GuidGenerator NullReferenceException in UnitTest #7365


User avatar
0
PDarioJer created

When I call GuidGenerator.Create() in my DomainService, that I instantiated in a test, I get a NullReferenceException. I think I could solve this by implementing the IDomainService instead and then mock the IGuidGenerator interface. However, there really is no need to do that here aside from testing concerns.

Do you have any suggestions on how to workaround this issue?

(ItemManager.cs)

using System.Collections.Generic;
using System.Threading.Tasks;
using Volo.Abp.Domain.Services;

namespace TestPlatform.Items;
public class ItemManager : DomainService
{
	private readonly IItemRepository _itemRepository;

	public ItemManager(IItemRepository itemRepository)
	{
		_itemRepository = itemRepository;
	}

	public async Task<Item> CreateAsync(
		string itemNr,
		int variantCode,
		string description,
	)
	{
		var existingItem = await _itemRepository.FindByItemNrAndVariantAsync(itemNr, variantCode);
		if (existingItem != null)
		{
			throw new ItemAlreadyExistsException(itemNr, variantCode);
		}

		var newGuid = GuidGenerator.Create();
		return new Item(
			newGuid,
			itemNr,
			variantCode,
			description,
		);
	}
}

(ItemManagerTest.cs)

using System.Threading.Tasks;
using TestPlatform.Items.Shared;
using NSubstitute;
using NSubstitute.ReturnsExtensions;
using Shouldly;
using Xunit;

namespace TestPlatform.Items;
public class ItemManager_CreateAsyncShould
{
	private IItemRepository itemRepository = Substitute.For<IItemRepository>();

	[Fact]
	public async Task Return_Item_If_No_Item_With_Same_ItemNr_Exists()
	{
		itemRepository.FindByItemNrAndVariantAsync(
			ValidItemData.ItemNr,
			ValidItemData.VariantCode
		).ReturnsNull();
		var itemManager = new ItemManager(itemRepository);

		var item = await itemManager.CreateAsync(
			ValidItemData.ItemNr,
			ValidItemData.VariantCode,
			ValidItemData.Description,
		);

		item.ShouldBeOfType<Item>();
		item.ShouldNotBeNull();
	}
}
  • ABP Framework version: v8.1.3
  • UI Type: Blazor Server
  • Database System: EF Core (SQL Server)
  • Tiered: no
  • Exception message and full stack trace: System.NullReferenceException : Object reference not set to an instance of an object.
  • ItemManager.CreateAsync(String itemNr, Int32 variantCode, String description) Zeile 27 ItemManager_CreateAsyncShould.Return_Item_If_No_Item_With_Same_ItemNr_Exists() Zeile 22 --- End of stack trace from previous location ---
  • Steps to reproduce the issue: Call GuidGenerator.Create() from within a testing context

Edit: For some reason, markdown removes everything inside the <> arrows. However, the content is not important for the problem at hand anyway.


5 Answer(s)
  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    hi

    var itemManager = new ItemManager(itemRepository)

    You can consider getting services from DI(ServiceProvider)

    If you want to create an instance manually, You have to set its properties manually.

    var itemManager = new ItemManager(itemRepository)
    ObjectHelper.TrySetProperty(
        itemManager,
        x => x.GuidGenerator,
        () => new GuidGenerator()
    );
    
  • User Avatar
    0
    PDarioJer created

    Unfortunately, the GuidGenerator is a protected property, so I won't be able to set it manually. Getting the ItemManager through DI is an option, however, I don't want it to use the actual ItemRepository but a Substitute, so I can return a fake return value on the FindByItemNrAndVariantAsync(...) method.

    My question here is: Is there a way to provide the domain service with an implementation of the GuidGenerator without using the IDomainService interface? Or alternatively, is there a way to get the ItemManager through dependency injection but with a mocked ItemRepository?

  • User Avatar
    1
    maliming created
    Support Team Fullstack Developer

    hi

    Or alternatively, is there a way to get the ItemManager through dependency injection but with a mocked ItemRepository?

    Yes, You just need to add a mock service to DI to replace the built-in service.

    https://github.com/abpframework/abp/blob/dev/modules/cms-kit/test/Volo.CmsKit.Application.Tests/Reactions/ReactionPublicAppService_Tests.cs#L25-L29

  • User Avatar
    0
    PDarioJer created

    Thank you, this helped!

  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    : )

Made with ❤️ on ABP v9.1.0-preview. Updated on November 20, 2024, 13:06