System.ArgumentException: Can not instantiate proxy of class: Atlassian.Jira.Jira – How to write Unit Tests for JIRA Services in .NET?

  Kiến thức lập trình

I have this Service which is responsible for fetching and creating JIRA tickets.

public class TcJiraService(Jira tJiraClient, IOptions<TcJiraOptions> tOptions, ILogger<TcJiraService> tLogger)
{
    private readonly TcJiraOptions mOptions = tOptions.Value;

    public async Task<List<Issue>> GetJiraIssuesAsync()
    {
        try
        {
            var aJqlQuery = $"project = '{mOptions.ProjectKey}'";
            var aIssues = await tJiraClient.Issues.GetIssuesFromJqlAsync(aJqlQuery);
            foreach (var aIssue in aIssues)
            {
                tLogger.LogInformation("Issue Key: {aIssue.Key}, Summary: {aIssue.Summary}", aIssue.Key, aIssue.Summary);
            }
            return aIssues.ToList();
        }
        catch (Exception aEx)
        {
            tLogger.LogError("An error occurred while fetching issues from JIRA: {Message}", aEx.Message);
            return [];
        }
    }

    public async Task<string?> CreateJiraIssueAsync(string? tSummary, string? tDescription, string? tEmailSender)
    {
        try
        {
            var aIssue = tJiraClient.CreateIssue(mOptions.ProjectKey);
            aIssue.Type = new IssueType("9");
            aIssue.Priority = new IssuePriority("5");
            aIssue.Summary = tSummary;
            aIssue.Description = tDescription;
            await aIssue.SaveChangesAsync();
            return aIssue.Key.Value;
        }
        catch (Exception aEx)
        {
            tLogger.LogError("Failed to create JIRA issue: {Message}", aEx.Message);
            return null;
        }
    }

    public async Task<bool> AttachContentToIssueAsync(string tIssueKey, byte[] tContentData, string tFileName)
    {
        try
        {
            var aIssue = await tJiraClient.Issues.GetIssueAsync(tIssueKey);
            var aAttachment = new UploadAttachmentInfo(tFileName, tContentData);
            await aIssue.AddAttachmentAsync([aAttachment]);
            return true;
        }
        catch (Exception aEx)
        {
            tLogger.LogError("Failed to attach file to JIRA issue. {Message}", aEx.Message);
            return false;
        }
    }
}

I’m using the package Atlassian.Jira to create a JIRA client (in my ConfigurationServices as a Singleton).

The code works but I am struggling writing Unit Tests for it.

My current test:

public class TcJiraServiceTest
{
    private readonly Mock<Jira> mockJiraClient = new Mock<Jira>();
    private readonly Mock<ILogger<TcJiraService>> mockLogger = new Mock<ILogger<TcJiraService>>();
    private readonly IOptions<TcJiraOptions> mockOptions = Options.Create(new TcJiraOptions
    {
        ProjectKey = "TEST-1",
        BaseUrl = "example.com"
    });

    private TcJiraService service;

    public TcJiraServiceTest()
    {
        this.service = new TcJiraService(mockJiraClient.Object, mockOptions, mockLogger.Object);
    }

    [Fact]
    public async Task CreateJiraIssueAsync_ReturnsIssueKey_WhenCalledWithValidParameters()
    {
        // Arrange
        var fakeIssue = new Mock<Issue>(mockJiraClient.Object, "TEST", "1"); 
        fakeIssue.Setup(issue => issue.Key).Returns("TEST-1");

        // Act
        var issueKey = await service.CreateJiraIssueAsync("Test Summary", "Test Description", "[email protected]");

        // Assert
        Assert.Equal("TEST-1", issueKey);
    }
    
}

I try to mock the JIRA Client but cannot instantiate it because I get this error

System.ArgumentException: Can not instantiate proxy of class: Atlassian.Jira.Jira.

System.ArgumentException
Can not instantiate proxy of class: Atlassian.Jira.Jira.
Could not find a parameterless constructor. (Parameter 'constructorArguments')
   at Castle.DynamicProxy.ProxyGenerator.CreateClassProxyInstance(Type proxyType, List`1 proxyArguments, Type classToProxy, Object[] constructorArguments)
   at Castle.DynamicProxy.ProxyGenerator.CreateClassProxy(Type classToProxy, Type[] additionalInterfacesToProxy, ProxyGenerationOptions options, Object[] constructorArguments, IInterceptor[] interceptors)
   at Moq.CastleProxyFactory.CreateProxy(Type mockType, IInterceptor interceptor, Type[] interfaces, Object[] arguments) in /_/src/Moq/Interception/CastleProxyFactory.cs:line 110
   at Moq.Mock`1.InitializeInstance() in /_/src/Moq/Mock`1.cs:line 502
   at Moq.Mock`1.OnGetObject() in /_/src/Moq/Mock`1.cs:line 516
   at Moq.Mock.get_Object() in /_/src/Moq/Mock.cs:line 180
   at Moq.Mock`1.get_Object() in /_/src/Moq/Mock`1.cs:line 453
   at TcJiraServiceTest..ctor() in C:Usersvuso1RiderProjectsNewNeuer Ordnertrumpf.mailserveraccesssrcTrumpf.MailServerAccess.TestsTcJiraServiceTest.cs:line 22
   at System.RuntimeType.CreateInstanceDefaultCtor(Boolean publicOnly, Boolean wrapExceptions)

System.MissingMethodException
Constructor on type 'Castle.Proxies.JiraProxy' not found.
   at System.RuntimeType.CreateInstanceImpl(BindingFlags bindingAttr, Binder binder, Object[] args, CultureInfo culture)
   at Castle.DynamicProxy.ProxyGenerator.CreateClassProxyInstance(Type proxyType, List`1 proxyArguments, Type classToProxy, Object[] constructorArguments)

Probably MOQ cannot mock concrete classes?
I also adjusted my code and used Interfaces but still get the same error.
Any other idea?

Before I used the JIRA Client, I used HttpClient in my JiraService to connect to the JIRA server, with this approach I could write tests as I could mock the HttpClient but now switching to JIRA client directly, I don’t know how to mock it.

LEAVE A COMMENT