Skip to content

Commit

Permalink
adding some missing unit tests
Browse files Browse the repository at this point in the history
  • Loading branch information
mgroves committed Sep 11, 2023
1 parent f04b846 commit 0807d3f
Show file tree
Hide file tree
Showing 7 changed files with 262 additions and 1 deletion.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -334,3 +334,4 @@ appsettings.Development.json
appsettings.Production.json
/Conduit/migrateup.bat
/Conduit/Conduit.Tests/integrationtestsettings.json
/Conduit/*.lutconfig
2 changes: 1 addition & 1 deletion Conduit/Conduit.Tests/Conduit.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
<PackageReference Include="Moq" Version="4.18.4" />
<PackageReference Include="NoSqlMigrator" Version="0.0.3-alpha" />
<PackageReference Include="NUnit" Version="3.13.3" />
<PackageReference Include="NUnit3TestAdapter" Version="4.4.2" />
<PackageReference Include="NUnit3TestAdapter" Version="4.5.0" />
<PackageReference Include="NUnit.Analyzers" Version="3.6.1" />
<PackageReference Include="coverlet.collector" Version="3.2.0" />
</ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,4 +47,26 @@ public async Task Favoriting_works_and_increases_count(int initialCount, int exp
Assert.That(x.FavoritesCount, Is.EqualTo(expectedCount));
});
}

[Test]
[Ignore("TXNN-134 see comments")]
public async Task Favoriting_an_already_favorited_article_does_not_change_the_favorites()
{
// might be a BUG https://issues.couchbase.com/browse/TXNN-134
// or could be user error - ignoring this test until I can resolve that issue

// arrange
var article = await _articleCollectionProvider.CreateArticleInDatabase();
var user = UserHelper.CreateUser();
await _articleDataService.Favorite(article.Slug, user.Username);

// act
await _articleDataService.Favorite(article.Slug, user.Username);

// assert
await _favoriteCollectionProvider.AssertExists(user.Username, x =>
{
Assert.That(x.Count, Is.EqualTo(1));
});
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
using Conduit.Web.Articles.Handlers;
using Conduit.Web.Articles.Services;
using Moq;

namespace Conduit.Tests.Unit.Articles.Handlers;

[TestFixture]
public class FavoriteArticleHandlerTests
{
private Mock<IArticlesDataService> _articleDataServiceMock;
private FavoriteArticleHandler _handler;

[SetUp]
public async Task Setup()
{
_articleDataServiceMock = new Mock<IArticlesDataService>();

_handler = new FavoriteArticleHandler(
_articleDataServiceMock.Object);
}

[Test]
public async Task If_article_exists_it_can_be_favorited()
{
// arrange
var slug = "valid-slug::a8as9d89ads";
var username = "valid-username";
_articleDataServiceMock.Setup(m => m.Exists(slug))
.ReturnsAsync(true);
var request = new FavoriteArticleRequest
{
Slug = slug,
Username = username
};

// act
var result = await _handler.Handle(request, CancellationToken.None);

// assert
Assert.That(result.ValidationErrors == null || !result.ValidationErrors.Any(), Is.True);
}

[Test]
public async Task If_article_doest_exists_then_invalid_request()
{
// arrange
var slug = "valid-slug::f9ad09fads";
var username = "valid-username-too";
_articleDataServiceMock.Setup(m => m.Exists(slug))
.ReturnsAsync(false);
var request = new FavoriteArticleRequest
{
Slug = slug,
Username = username
};

// act
var result = await _handler.Handle(request, CancellationToken.None);

// assert
Assert.That(result.ValidationErrors, Is.Not.Null);
Assert.That(result.ValidationErrors, Is.Not.Empty);
Assert.That(result.ValidationErrors.Count, Is.EqualTo(1));
Assert.That(result.ValidationErrors[0].ErrorMessage, Is.EqualTo("Article not found."));
}
}
132 changes: 132 additions & 0 deletions Conduit/Conduit.Tests/Unit/Articles/Handlers/GetArticleHandlerTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
using Conduit.Tests.TestHelpers.Data;
using Conduit.Web.Articles.Handlers;
using Conduit.Web.Articles.Services;
using Conduit.Web.DataAccess.Dto;
using Conduit.Web.DataAccess.Models;
using Conduit.Web.Follows.Services;
using Conduit.Web.Users.Services;
using Moq;

namespace Conduit.Tests.Unit.Articles.Handlers;

[TestFixture]
public class GetArticleHandlerTests
{
private Mock<IArticlesDataService> _articleDataServiceMock;
private GetArticleHandler _handler;
private Mock<IUserDataService> _usersDataServiceMock;
private Mock<IFollowDataService> _followsDataServiceMock;

[SetUp]
public async Task Setup()
{
_articleDataServiceMock = new Mock<IArticlesDataService>();
_usersDataServiceMock = new Mock<IUserDataService>();
_followsDataServiceMock = new Mock<IFollowDataService>();

// mock defaults
_followsDataServiceMock.Setup(m => m.IsCurrentUserFollowing(It.IsAny<string>(), It.IsAny<string>()))
.ReturnsAsync(true);
_articleDataServiceMock.Setup(m => m.IsFavorited(It.IsAny<string>(), It.IsAny<string>()))
.ReturnsAsync(true);

_handler = new GetArticleHandler(
_articleDataServiceMock.Object,
_usersDataServiceMock.Object,
_followsDataServiceMock.Object);
}

[Test]
public async Task When_article_exists_return_a_view_of_it_and_author()
{
// arrange
var author = UserHelper.CreateUser();
var article = ArticleHelper.CreateArticle(authorUsername: author.Username);
var request = new GetArticleRequest(article.Slug, "valid-username");
_articleDataServiceMock.Setup(m => m.Exists(article.Slug))
.ReturnsAsync(true);
_articleDataServiceMock.Setup(m => m.Get(article.Slug))
.ReturnsAsync(new DataServiceResult<Article>(article, DataResultStatus.Ok));
_usersDataServiceMock.Setup(m => m.GetProfileByUsername(author.Username))
.ReturnsAsync(new DataServiceResult<User>(author, DataResultStatus.Ok));

// act
var result = await _handler.Handle(request, CancellationToken.None);

// assert
Assert.That(result.ArticleView, Is.Not.Null);
Assert.That(result.ValidationErrors == null || !result.ValidationErrors.Any(), Is.True);
}

[Test]
public async Task Invalid_when_article_doesnt_exist()
{
// arrange
var request = new GetArticleRequest("doesnt-matter", "valid-username");
_articleDataServiceMock.Setup(m => m.Exists(It.IsAny<string>()))
.ReturnsAsync(false);

// act
var result = await _handler.Handle(request, CancellationToken.None);

// assert
Assert.That(result.ValidationErrors != null && result.ValidationErrors.Any(), Is.True);
Assert.That(result.ValidationErrors.Count, Is.EqualTo(1));
Assert.That(result.ValidationErrors[0].ErrorMessage, Is.EqualTo("Article not found."));
}

[Test]
public async Task When_user_not_authenticated_following_and_favorited_default_to_false()
{
// arrange
var author = UserHelper.CreateUser();
var article = ArticleHelper.CreateArticle(authorUsername: author.Username);
var request = new GetArticleRequest(article.Slug, null);
_articleDataServiceMock.Setup(m => m.Exists(article.Slug))
.ReturnsAsync(true);
_articleDataServiceMock.Setup(m => m.Get(article.Slug))
.ReturnsAsync(new DataServiceResult<Article>(article, DataResultStatus.Ok));
_usersDataServiceMock.Setup(m => m.GetProfileByUsername(author.Username))
.ReturnsAsync(new DataServiceResult<User>(author, DataResultStatus.Ok));

// act
var result = await _handler.Handle(request, CancellationToken.None);

// assert
Assert.That(result.ArticleView, Is.Not.Null);
Assert.That(result.ValidationErrors == null || !result.ValidationErrors.Any(), Is.True);
Assert.That(result.ArticleView.Favorited, Is.False);
Assert.That(result.ArticleView.Author.Following, Is.False);
}

[TestCase(true, false)]
[TestCase(false, true)]
[TestCase(true, true)]
[TestCase(false, false)]
public async Task When_returning_article_to_authenticated_user_following_and_favorited_are_set(bool isFollowing, bool isFavorited)
{
// arrange
var author = UserHelper.CreateUser();
var article = ArticleHelper.CreateArticle(authorUsername: author.Username);
var request = new GetArticleRequest(article.Slug, "valid-username");
_articleDataServiceMock.Setup(m => m.Exists(article.Slug))
.ReturnsAsync(true);
_articleDataServiceMock.Setup(m => m.Get(article.Slug))
.ReturnsAsync(new DataServiceResult<Article>(article, DataResultStatus.Ok));
_usersDataServiceMock.Setup(m => m.GetProfileByUsername(author.Username))
.ReturnsAsync(new DataServiceResult<User>(author, DataResultStatus.Ok));
_followsDataServiceMock.Setup(m => m.IsCurrentUserFollowing(It.IsAny<string>(), It.IsAny<string>()))
.ReturnsAsync(isFollowing);
_articleDataServiceMock.Setup(m => m.IsFavorited(It.IsAny<string>(), It.IsAny<string>()))
.ReturnsAsync(isFavorited);

// act
var result = await _handler.Handle(request, CancellationToken.None);

// assert
Assert.That(result.ArticleView, Is.Not.Null);
Assert.That(result.ValidationErrors == null || !result.ValidationErrors.Any(), Is.True);
Assert.That(result.ArticleView.Author.Following, Is.EqualTo(isFollowing));
Assert.That(result.ArticleView.Favorited, Is.EqualTo(isFavorited));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -222,4 +222,40 @@ public async Task All_fields_are_optional_and_null_means_no_change_but_at_least_
Assert.That(result.ValidationErrors, Is.Not.Null);
Assert.That(result.ValidationErrors.Any(e => e.ErrorMessage == "Update Failed: Please make sure to modify at least one of the following fields: Body, Title, Description, or Tags."));
}

[Test]
public async Task Returns_NotFound_if_article_doesnt_exist()
{
// arrange
var model = UpdateArticlePostModelHelper.Create();
model.Article.Tags = new List<string> { "tag1" };
var request = UpdateArticleRequestHelper.Create(model: model);
_articlesDataServiceMock.Setup(m => m.Get(request.Slug))
.ReturnsAsync(new DataServiceResult<Article>(null, DataResultStatus.NotFound));

// act
var result = await _handler.Handle(request, CancellationToken.None);

// assert
Assert.That(result, Is.Not.Null);
Assert.That(result.IsNotFound, Is.True);
}

[Test]
public async Task Returns_NotAuthorized_if_non_author_is_trying_to_update()
{
// arrange
var model = UpdateArticlePostModelHelper.Create();
model.Article.Tags = new List<string> { "tag1" };
var request = UpdateArticleRequestHelper.Create(model: model);
_articlesDataServiceMock.Setup(m => m.IsArticleAuthor(It.IsAny<string>(), It.IsAny<string>()))
.ReturnsAsync(false);

// act
var result = await _handler.Handle(request, CancellationToken.None);

// assert
Assert.That(result, Is.Not.Null);
Assert.That(result.IsNotAuthorized, Is.True);
}
}
4 changes: 4 additions & 0 deletions Conduit/Conduit.Web/Articles/Services/ArticlesDataService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,7 @@ public async Task Favorite(string slug, string username)
// check to see if user has already favorited this article (if they have, bail out)
var favoritesDoc = await context.GetAsync(favoriteCollection, favoriteKey);
var favorites = favoritesDoc.ContentAs<List<string>>();
// BUG? https://issues.couchbase.com/browse/TXNN-134
if (favorites.Contains(slug.GetArticleKey()))
{
await context.RollbackAsync();
Expand All @@ -199,7 +200,10 @@ public async Task Favorite(string slug, string username)
var article = articleDoc.ContentAs<Article>();
article.FavoritesCount++;
await context.ReplaceAsync(articleDoc, article);
await context.CommitAsync();
});

await transaction.DisposeAsync();
}

private async Task EnsureFavoritesDocumentExists(string username)
Expand Down

0 comments on commit 0807d3f

Please sign in to comment.