I am really new to XUnit and I will appreciate some help.
Controller
I have a really simple API method that adds a bug comment
[HttpPost("{bugId}/comment")]
public async Task<IActionResult> AddComment(Guid bugId, [FromBody] AddCommentForm form)
{
return await _bugService.AddComment(bugId, form) switch
{
Option<BugViewModel>.Some(var bug) => Ok(bug),
Option<BugViewModel>.None => NotFound(),
_ => throw new InvalidOperationException()
};
}
Service
The BugService method AddComment looks like this
public async Task<Option<BugViewModel>> AddComment(Guid bugId, AddCommentForm form)
{
if (await DbBugs.SingleOrDefaultAsync(x => x.Id == bugId) is { } bug)
{
var bugComment = new BugComment
{
Text = form.Text,
Commenter = form.Commenter,
CommentedAt = DateTime.Now,
Bug = bug
};
await _dbContext.BugComments.AddAsync(bugComment);
await _dbContext.SaveChangesAsync();
return new Option<BugViewModel>.Some(BugViewModel.FromData(bug));
}
return new Option<BugViewModel>.None();
}
ViewModels
I am adding the implementation of BugViewModel and BugCommentViewModel with their static FromData methods
public class BugViewModel
{
public Guid Id { get; set; }
public string Title { get; set; }
public string Description { get; set; }
public List<BugCommentViewModel> Comments { get; set; }
public static BugViewModel FromData(Bug bug)
{
return new BugViewModel
{
Id = bug.Id,
Title = bug.Title,
Description = bug.Description,
Comments = bug.Comments.Select(BugCommentViewModel.FromData).ToList()
};
}
}
public class BugCommentViewModel
{
public Guid Id { get; set; }
public string Text { get; set; }
public string Commenter { get; set; }
public DateTime CommentedAt { get; set; }
public static BugCommentViewModel FromData(BugComment comment)
{
return new BugCommentViewModel
{
Id = comment.Id,
Text = comment.Text,
Commenter = comment.Commenter,
CommentedAt = comment.CommentedAt.ToLocalTime()
};
}
}
Testing
The Unit Tests look like this
public class BugContollerTests
{
private class Fixture
{
public IBugService BugService { get; } = Substitute.For<IBugService>();
public BugController GetSut() => new BugController(BugService);
}
private readonly Fixture _fixture = new Fixture();
[Fact]
public async Task Create_ResponseBodyIsCreatedBug()
{
var bug = BugViewModel.FromData(FakeBug.I.Generate());
_fixture.BugService.Create(Arg.Any<CreateBugForm>()).Returns(bug);
var sut = _fixture.GetSut();
var response = Assert.IsAssignableFrom<CreatedAtActionResult>(await sut.Create(new CreateBugForm()));
Assert.Same(bug, response.Value);
}
[Fact]
public async Task AddComment_CommentIsAddedtoViewModel()
{
_fixture.BugService.AddComment(Arg.Any<Guid>(), Arg.Any<AddCommentForm>()).Returns(new Option<BugViewModel>.Some(new BugViewModel()));
var sut = _fixture.GetSut();
var response = Assert.IsAssignableFrom<ObjectResult>(await sut.AddComment(Guid.Empty,new AddCommentForm()));
Assert.Single(((BugViewModel) response.Value).Comments);
}
}
So, the Test method I had as an example was Create_ResponseBodyIsCreatedBug but the question I have is regarding the second test method that I have created AddComment_CommentIsAddedtoViewModel().
What I am trying to do is:
you see that the BugService.AddComment -> it adds the comment with the Bug Guid we have provided and basically we return BugViewModel with that Comment added to the Comments collection.
test: that WHEN I add a BugComment it is returned in the ViewModel response and we have added exactly one Comment to the bug.
this line
var response = Assert.IsAssignableFrom<ObjectResult>(await sut.AddComment(Guid.Empty,new AddCommentForm()));
the response.Value is a BugViewModel with empty properties and the Comment property is empty without my inserted comment.
And on this line I get an exception as
Assert.Single(((BugViewModel) response.Value).Comments);
as the Comments property is null.