Skip to content

Commit

Permalink
100% coverage on usecases comments & favorites
Browse files Browse the repository at this point in the history
  • Loading branch information
Matthieu Jacquot committed Aug 10, 2018
1 parent 56b00dc commit e6c2ad9
Show file tree
Hide file tree
Showing 10 changed files with 389 additions and 98 deletions.
71 changes: 0 additions & 71 deletions uc/comments.go

This file was deleted.

28 changes: 28 additions & 0 deletions uc/commentsDelete.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package uc

func (i interactor) CommentsDelete(username, slug string, id int) error {
comment, err := i.commentRW.GetByID(id)
if err != nil {
return err
}
if comment.Author.Name != username {
return errWrongUser
}

if err := i.commentRW.Delete(id); err != nil {
return err
}

article, err := i.articleRW.GetBySlug(slug)
if err != nil {
return err
}

article.UpdateComments(*comment, false)

if _, err := i.articleRW.Save(*article); err != nil {
return err
}

return nil
}
93 changes: 93 additions & 0 deletions uc/commentsDelete_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
package uc_test

import (
"testing"

"errors"

"github.com/err0r500/go-realworld-clean/domain"
"github.com/err0r500/go-realworld-clean/implem/uc.mock"
"github.com/err0r500/go-realworld-clean/testData"
"github.com/golang/mock/gomock"
"github.com/stretchr/testify/assert"
)

func TestInteractor_CommentsDelete_happycase(t *testing.T) {
mockCtrl := gomock.NewController(t)
defer mockCtrl.Finish()

user := testData.User("rick")
article := testData.Article("jane")
comment := article.Comments[0]
articleWithoutTheComment := article
articleWithoutTheComment.Comments = []domain.Comment{}

i := mock.NewMockedInteractor(mockCtrl)
i.CommentRW.EXPECT().GetByID(comment.ID).Return(&comment, nil)
i.CommentRW.EXPECT().Delete(comment.ID).Return(nil)
i.ArticleRW.EXPECT().GetBySlug(article.Slug).Return(&article, nil)
i.ArticleRW.EXPECT().Save(articleWithoutTheComment)

assert.NoError(t, i.GetUCHandler().CommentsDelete(user.Name, article.Slug, comment.ID))
}

func TestInteractor_CommentsDelete_fails(t *testing.T) {
mutations := map[string]mock.Tester{
"shouldPass": {
Calls: func(i *mock.Interactor) { // change nothing
},
ShouldPass: true},
"failed to get comment by ID": {
Calls: func(i *mock.Interactor) {
i.CommentRW.EXPECT().GetByID(gomock.Any()).Return(nil, errors.New(""))
}},
"returned a comment belonging to another user": {
Calls: func(i *mock.Interactor) {
i.CommentRW.EXPECT().GetByID(gomock.Any()).Return(&domain.Comment{Author: domain.User{Name: "hey"}}, nil)
}},
"failed to delete comment": {
Calls: func(i *mock.Interactor) {
i.CommentRW.EXPECT().Delete(gomock.Any()).Return(errors.New(""))
}},
"failed to get article by slug comment": {
Calls: func(i *mock.Interactor) {
i.ArticleRW.EXPECT().GetBySlug(gomock.Any()).Return(nil, errors.New(""))
}},
"failed to save article": {
Calls: func(i *mock.Interactor) {
i.ArticleRW.EXPECT().Save(gomock.Any()).Return(nil, errors.New(""))
}},
}

user := testData.User("rick")
article := testData.Article("jane")
comment := article.Comments[0]
articleWithoutTheComment := article
articleWithoutTheComment.Comments = []domain.Comment{}

// same as the happy case but with any parameter and called any number of times (including 0)
validCalls := func(i *mock.Interactor) {
i.CommentRW.EXPECT().GetByID(gomock.Any()).Return(&comment, nil).AnyTimes()
i.CommentRW.EXPECT().Delete(gomock.Any()).Return(nil).AnyTimes()
i.ArticleRW.EXPECT().GetBySlug(gomock.Any()).Return(&article, nil).AnyTimes()
i.ArticleRW.EXPECT().Save(gomock.Any()).AnyTimes()

}

for testName, mutation := range mutations {
t.Run(testName, func(t *testing.T) {
mockCtrl := gomock.NewController(t)
defer mockCtrl.Finish()
i := mock.NewMockedInteractor(mockCtrl)
mutation.Calls(&i) // put the tested call first (important)
validCalls(&i) // then fill the gaps with valid calls

err := i.GetUCHandler().CommentsDelete(user.Name, article.Slug, comment.ID)
if mutation.ShouldPass {
assert.NoError(t, err)
return
}
assert.Error(t, err)
})
}
}
12 changes: 12 additions & 0 deletions uc/commentsGet.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package uc

import "github.com/err0r500/go-realworld-clean/domain"

func (i interactor) CommentsGet(slug string) ([]domain.Comment, error) {
article, err := i.articleRW.GetBySlug(slug)
if err != nil {
return nil, err
}

return article.Comments, nil
}
40 changes: 40 additions & 0 deletions uc/commentsGet_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package uc_test

import (
"testing"

"errors"

"github.com/err0r500/go-realworld-clean/implem/uc.mock"
"github.com/err0r500/go-realworld-clean/testData"
"github.com/golang/mock/gomock"
"github.com/stretchr/testify/assert"
)

func TestInteractor_CommentsGet(t *testing.T) {
mockCtrl := gomock.NewController(t)
defer mockCtrl.Finish()

article := testData.Article("jane")

i := mock.NewMockedInteractor(mockCtrl)
i.ArticleRW.EXPECT().GetBySlug(article.Slug).Return(&article, nil)

comments, err := i.GetUCHandler().CommentsGet(article.Slug)
assert.NoError(t, err)
assert.Equal(t, article.Comments, comments)
}

func TestInteractor_CommentsGet_fails(t *testing.T) {
mockCtrl := gomock.NewController(t)
defer mockCtrl.Finish()

article := testData.Article("jane")

i := mock.NewMockedInteractor(mockCtrl)
i.ArticleRW.EXPECT().GetBySlug(article.Slug).Return(nil, errors.New(""))

comments, err := i.GetUCHandler().CommentsGet(article.Slug)
assert.Error(t, err)
assert.Nil(t, comments)
}
33 changes: 33 additions & 0 deletions uc/commentsPost.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package uc

import "github.com/err0r500/go-realworld-clean/domain"

func (i interactor) CommentsPost(username, slug, comment string) (*domain.Comment, error) {
commentPoster, err := i.userRW.GetByName(username)
if err != nil {
return nil, err
}

article, err := i.articleRW.GetBySlug(slug)
if err != nil {
return nil, err
}

rawComment := domain.Comment{
Body: comment,
Author: *commentPoster,
}

insertedComment, err := i.commentRW.Create(rawComment)
if err != nil {
return nil, err
}

article.Comments = append(article.Comments, *insertedComment)

if _, err := i.articleRW.Save(*article); err != nil {
return nil, err
}

return insertedComment, nil
}
93 changes: 93 additions & 0 deletions uc/commentsPost_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
package uc_test

import (
"testing"

"errors"

"github.com/err0r500/go-realworld-clean/domain"
"github.com/err0r500/go-realworld-clean/implem/uc.mock"
"github.com/err0r500/go-realworld-clean/testData"
"github.com/golang/mock/gomock"
"github.com/stretchr/testify/assert"
)

func TestInteractor_CommentsPost_happycase(t *testing.T) {
mockCtrl := gomock.NewController(t)
defer mockCtrl.Finish()

user := testData.User("rick")
article := testData.Article("jane")
articleWithoutComment := article
articleWithoutComment.Comments = []domain.Comment{} //reset comments
comment := article.Comments[0]

i := mock.NewMockedInteractor(mockCtrl)
i.UserRW.EXPECT().GetByName(user.Name).Return(&user, nil)
i.ArticleRW.EXPECT().GetBySlug(article.Slug).Return(&articleWithoutComment, nil)
i.CommentRW.EXPECT().Create(domain.Comment{Body: comment.Body, Author: user}).Return(&comment, nil)
i.ArticleRW.EXPECT().Save(article)

returnedComment, err := i.GetUCHandler().CommentsPost(user.Name, article.Slug, comment.Body)
assert.NoError(t, err)
assert.Equal(t, comment, *returnedComment)
}

func TestInteractor_CommentsPost_fails(t *testing.T) {
mutations := map[string]mock.Tester{
"shouldPass": {
Calls: func(i *mock.Interactor) { // change nothing
},
ShouldPass: true},
"failed get user by name": {
Calls: func(i *mock.Interactor) {
i.UserRW.EXPECT().GetByName(gomock.Any()).Return(nil, errors.New(""))
},
},
"failed get by slug": {
Calls: func(i *mock.Interactor) {
i.ArticleRW.EXPECT().GetBySlug(gomock.Any()).Return(nil, errors.New(""))
},
},
"failed get create comment": {
Calls: func(i *mock.Interactor) {
i.CommentRW.EXPECT().Create(gomock.Any()).Return(nil, errors.New(""))
},
},
"failed save article": {
Calls: func(i *mock.Interactor) {
i.ArticleRW.EXPECT().Save(gomock.Any()).Return(nil, errors.New(""))
},
},
}
user := testData.User("rick")
article := testData.Article("jane")
articleWithoutComment := article
articleWithoutComment.Comments = []domain.Comment{} //reset comments
comment := article.Comments[0]

// same as the happy case but with any parameter and called any number of times (including 0)
validCalls := func(i *mock.Interactor) {
i.UserRW.EXPECT().GetByName(gomock.Any()).Return(&user, nil).AnyTimes()
i.ArticleRW.EXPECT().GetBySlug(gomock.Any()).Return(&articleWithoutComment, nil).AnyTimes()
i.CommentRW.EXPECT().Create(gomock.Any()).Return(&comment, nil).AnyTimes()
i.ArticleRW.EXPECT().Save(gomock.Any()).AnyTimes()
}

for testName, mutation := range mutations {
t.Run(testName, func(t *testing.T) {
mockCtrl := gomock.NewController(t)
defer mockCtrl.Finish()
i := mock.NewMockedInteractor(mockCtrl)
mutation.Calls(&i) // put the tested call first (important)
validCalls(&i) // then fill the gaps with valid calls

_, err := i.GetUCHandler().CommentsPost(user.Name, article.Slug, comment.Body)
if mutation.ShouldPass {
assert.NoError(t, err)
return
}
assert.Error(t, err)
})
}
}
22 changes: 0 additions & 22 deletions uc/favorite_test.go

This file was deleted.

Loading

0 comments on commit e6c2ad9

Please sign in to comment.