From f260fe8eca61789dd2f5d19ef39924e8596a0867 Mon Sep 17 00:00:00 2001 From: Dawid Stuzynski Date: Sat, 1 Jul 2023 23:07:56 +0200 Subject: [PATCH 1/5] Weird behavior of tests --- .../it/move2/agent/application/Updater.kt | 13 +- .../agent/application/UpdaterTest.groovy | 239 ++++++++++++++++++ 2 files changed, 251 insertions(+), 1 deletion(-) create mode 100644 src/test/groovy/it/move2/agent/application/UpdaterTest.groovy diff --git a/src/main/kotlin/it/move2/agent/application/Updater.kt b/src/main/kotlin/it/move2/agent/application/Updater.kt index 50df407..2d6bbfc 100644 --- a/src/main/kotlin/it/move2/agent/application/Updater.kt +++ b/src/main/kotlin/it/move2/agent/application/Updater.kt @@ -1,9 +1,20 @@ package it.move2.agent.application import it.move2.agent.ports.JobBoard +import it.move2.job.JobOffer class Updater( private val jobBoards: List, private val publisher: Publisher ) { - fun execute() = jobBoards.map { it.getJobs() }.flatten().let { publisher.publish(it) } + // fun execute() = jobBoards.map { it.getJobs() }.flatten().let { publisher.publish(it) } + fun execute() { + val jobList = mutableListOf() + for (jobBoard in jobBoards) { + val jobs = jobBoard.getJobs() + for (job in jobs) { + jobList.add(job) + } + } + publisher.publish(jobList) + } } \ No newline at end of file diff --git a/src/test/groovy/it/move2/agent/application/UpdaterTest.groovy b/src/test/groovy/it/move2/agent/application/UpdaterTest.groovy new file mode 100644 index 0000000..0a1d97d --- /dev/null +++ b/src/test/groovy/it/move2/agent/application/UpdaterTest.groovy @@ -0,0 +1,239 @@ +package it.move2.agent.application + +import com.fasterxml.jackson.databind.ObjectMapper +import it.move2.agent.configuration.PublisherConfiguration +import it.move2.agent.ports.JobBoard +import it.move2.agent.ports.Queue +import it.move2.job.EmploymentType +import it.move2.job.JobOffer +import it.move2.job.Salary +import it.move2.job.Skill +import spock.lang.Specification +import spock.lang.Subject + +class UpdaterTest extends Specification { + + @Subject + private Updater updater + + private Publisher publisher + + private Queue queue + + private JobBoard jobBoard1 + private JobBoard jobBoard2 + + def setup() { + queue = Mock() + publisher = new Publisher(new PublisherConfiguration(2), new ObjectMapper(), queue) + jobBoard1 = Mock() + jobBoard2 = Mock() + updater = new Updater([jobBoard1, jobBoard2], publisher) + } + + + def "should publish jobs from all job boards"() { + + given: + jobBoard1.getJobs() >> getJobs1() + jobBoard2.getJobs() >> getJobs2() + queue.pub(_) >> {} + + when: + updater.execute() + + then: + 1 * publisher.publish(_) + } + + + private List getTestJobBoardList() { + return [ + new JobBoardImpl([ + new JobOffer( + "1", + "Software Engineer", + "Example Company", + "3+ years", + [ + new Skill("Java"), + new Skill("Python"), + new Skill("SQL") + ], + [ + new EmploymentType("Full-time", new Salary(50000, 80000, "USD")), +// new EmploymentType("Contract", null) + ], + true + ), + new JobOffer( + "2", + "Data Scientist", + "Another Company", + "5+ years", + [ + new Skill("Python"), + new Skill("Machine Learning"), + new Skill("Statistics") + ], + [ + new EmploymentType("Full-time", new Salary(60000, 90000, "USD")) + ], + false + ) + ]), + new JobBoardImpl([ + new JobOffer( + "1", + "Software Engineer", + "Example Company", + "3+ years", + [ + new Skill("Java"), + new Skill("Python"), + new Skill("SQL") + ], + [ + new EmploymentType("Full-time", new Salary(50000, 80000, "USD")), +// new EmploymentType("Contract", null) + ], + true + ), + new JobOffer( + "2", + "Data Scientist", + "Another Company", + "5+ years", + [ + new Skill("Python"), + new Skill("Machine Learning"), + new Skill("Statistics") + ], + [ + new EmploymentType("Full-time", new Salary(60000, 90000, "USD")) + ], + false + ) + ]), + new JobBoardImpl([ + new JobOffer( + "3", + "Front-end Developer", + "ABC Technologies", + "2+ years", + [ + new Skill("HTML"), + new Skill("CSS"), + new Skill("JavaScript") + ], + [ + new EmploymentType("Full-time", new Salary(40000, 60000, "USD")), +// new EmploymentType("Part-time", null) + ], + true + ), + new JobOffer( + "4", + "Marketing Specialist", + "XYZ Corporation", + "3+ years", + [ + new Skill("Digital Marketing"), + new Skill("Social Media Management"), + new Skill("Content Creation") + ], + [ + new EmploymentType("Full-time", new Salary(45000, 70000, "USD")), +// new EmploymentType("Freelance", null) + ], + false + ) + ]) + ] + } + + private List getJobs1() { + return [ + new JobOffer( + "1", + "Software Engineer", + "Example Company", + "3+ years", + [ + new Skill("Java"), + new Skill("Python"), + new Skill("SQL") + ], + [ + new EmploymentType("Full-time", new Salary(50000, 80000, "USD")), +// new EmploymentType("Contract", null) + ], + true + ), + new JobOffer( + "2", + "Data Scientist", + "Another Company", + "5+ years", + [ + new Skill("Python"), + new Skill("Machine Learning"), + new Skill("Statistics") + ], + [ + new EmploymentType("Full-time", new Salary(60000, 90000, "USD")) + ], + false + ) + ] + } + + private List getJobs2() { + return [ + new JobOffer( + "1", + "Software Engineer", + "Example Company", + "3+ years", + [ + new Skill("Java"), + new Skill("Python"), + new Skill("SQL") + ], + [ + new EmploymentType("Full-time", new Salary(50000, 80000, "USD")), +// new EmploymentType("Contract", null) + ], + true + ), + new JobOffer( + "2", + "Data Scientist", + "Another Company", + "5+ years", + [ + new Skill("Python"), + new Skill("Machine Learning"), + new Skill("Statistics") + ], + [ + new EmploymentType("Full-time", new Salary(60000, 90000, "USD")) + ], + false + ) + ] + } + + + class JobBoardImpl implements JobBoard { + private List jobOffers + + JobBoardImpl(List jobOffers) { + this.jobOffers = jobOffers + } + + List getJobs() { + return this.jobOffers + } + } +} \ No newline at end of file From c824a774debf5beaead2972e87ba204fda499833 Mon Sep 17 00:00:00 2001 From: Dawid Stuzynski Date: Fri, 7 Jul 2023 22:01:26 +0200 Subject: [PATCH 2/5] test: Add JobFixture --- .../move2/agent/application/JobFixture.groovy | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 src/test/groovy/it/move2/agent/application/JobFixture.groovy diff --git a/src/test/groovy/it/move2/agent/application/JobFixture.groovy b/src/test/groovy/it/move2/agent/application/JobFixture.groovy new file mode 100644 index 0000000..a549bf6 --- /dev/null +++ b/src/test/groovy/it/move2/agent/application/JobFixture.groovy @@ -0,0 +1,26 @@ +package it.move2.agent.application + +import it.move2.job.EmploymentType +import it.move2.job.JobOffer +import it.move2.job.Skill + +class JobFixture { + + static jobOffer(args = [:]) { + new JobOffer( + 'id' in args.keySet() ? args.id as String : 'test-id', + 'title' in args.keySet() ? args.title as String : 'test-title', + 'companyName' in args.keySet() ? args.companyName as String : 'test-company', + 'experience' in args.keySet() ? args.experience as String : 'test-experience', + 'skills' in args.keySet() ? args.skills as List : [], + 'employmentType' in args.keySet() ? args.employmentType as List : [], + 'remote' in args.keySet() ? args.remote as boolean : true + ) + } + + static List createListJobOffers(int count) { + return (1..count).collect { _ -> + jobOffer() + } + } +} \ No newline at end of file From c2da063c3c6629dad1edac880e9116c5af997943 Mon Sep 17 00:00:00 2001 From: Dawid Stuzynski Date: Fri, 7 Jul 2023 22:02:08 +0200 Subject: [PATCH 3/5] refactor: Make code functional --- .../kotlin/it/move2/agent/application/Updater.kt | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/src/main/kotlin/it/move2/agent/application/Updater.kt b/src/main/kotlin/it/move2/agent/application/Updater.kt index 2d6bbfc..50df407 100644 --- a/src/main/kotlin/it/move2/agent/application/Updater.kt +++ b/src/main/kotlin/it/move2/agent/application/Updater.kt @@ -1,20 +1,9 @@ package it.move2.agent.application import it.move2.agent.ports.JobBoard -import it.move2.job.JobOffer class Updater( private val jobBoards: List, private val publisher: Publisher ) { - // fun execute() = jobBoards.map { it.getJobs() }.flatten().let { publisher.publish(it) } - fun execute() { - val jobList = mutableListOf() - for (jobBoard in jobBoards) { - val jobs = jobBoard.getJobs() - for (job in jobs) { - jobList.add(job) - } - } - publisher.publish(jobList) - } + fun execute() = jobBoards.map { it.getJobs() }.flatten().let { publisher.publish(it) } } \ No newline at end of file From 1c963cee4edc6d14e4d2cc4e964978e80dec7524 Mon Sep 17 00:00:00 2001 From: Dawid Stuzynski Date: Fri, 7 Jul 2023 22:03:14 +0200 Subject: [PATCH 4/5] test: Implement tests for Updater --- .../agent/application/UpdaterTest.groovy | 231 ++---------------- 1 file changed, 27 insertions(+), 204 deletions(-) diff --git a/src/test/groovy/it/move2/agent/application/UpdaterTest.groovy b/src/test/groovy/it/move2/agent/application/UpdaterTest.groovy index 0a1d97d..c2f40d7 100644 --- a/src/test/groovy/it/move2/agent/application/UpdaterTest.groovy +++ b/src/test/groovy/it/move2/agent/application/UpdaterTest.groovy @@ -4,236 +4,59 @@ import com.fasterxml.jackson.databind.ObjectMapper import it.move2.agent.configuration.PublisherConfiguration import it.move2.agent.ports.JobBoard import it.move2.agent.ports.Queue -import it.move2.job.EmploymentType -import it.move2.job.JobOffer -import it.move2.job.Salary -import it.move2.job.Skill import spock.lang.Specification import spock.lang.Subject class UpdaterTest extends Specification { + private JobBoard jobBoard1 + private JobBoard jobBoard2 + private Queue queue + private ObjectMapper objectMapper + private Publisher publisher @Subject private Updater updater - private Publisher publisher - - private Queue queue - - private JobBoard jobBoard1 - private JobBoard jobBoard2 - def setup() { - queue = Mock() - publisher = new Publisher(new PublisherConfiguration(2), new ObjectMapper(), queue) jobBoard1 = Mock() jobBoard2 = Mock() + queue = Mock() + objectMapper = new ObjectMapper() + publisher = new Publisher(new PublisherConfiguration(2), objectMapper, queue) + updater = new Updater([jobBoard1, jobBoard2], publisher) } - def "should publish jobs from all job boards"() { - given: - jobBoard1.getJobs() >> getJobs1() - jobBoard2.getJobs() >> getJobs2() - queue.pub(_) >> {} + def jobs1 = [JobFixture.jobOffer(), JobFixture.jobOffer()] + def jobs2 = [JobFixture.jobOffer(), JobFixture.jobOffer()] + + jobBoard1.getJobs() >> jobs1 + jobBoard2.getJobs() >> jobs2 when: updater.execute() then: - 1 * publisher.publish(_) - } - + noExceptionThrown() - private List getTestJobBoardList() { - return [ - new JobBoardImpl([ - new JobOffer( - "1", - "Software Engineer", - "Example Company", - "3+ years", - [ - new Skill("Java"), - new Skill("Python"), - new Skill("SQL") - ], - [ - new EmploymentType("Full-time", new Salary(50000, 80000, "USD")), -// new EmploymentType("Contract", null) - ], - true - ), - new JobOffer( - "2", - "Data Scientist", - "Another Company", - "5+ years", - [ - new Skill("Python"), - new Skill("Machine Learning"), - new Skill("Statistics") - ], - [ - new EmploymentType("Full-time", new Salary(60000, 90000, "USD")) - ], - false - ) - ]), - new JobBoardImpl([ - new JobOffer( - "1", - "Software Engineer", - "Example Company", - "3+ years", - [ - new Skill("Java"), - new Skill("Python"), - new Skill("SQL") - ], - [ - new EmploymentType("Full-time", new Salary(50000, 80000, "USD")), -// new EmploymentType("Contract", null) - ], - true - ), - new JobOffer( - "2", - "Data Scientist", - "Another Company", - "5+ years", - [ - new Skill("Python"), - new Skill("Machine Learning"), - new Skill("Statistics") - ], - [ - new EmploymentType("Full-time", new Salary(60000, 90000, "USD")) - ], - false - ) - ]), - new JobBoardImpl([ - new JobOffer( - "3", - "Front-end Developer", - "ABC Technologies", - "2+ years", - [ - new Skill("HTML"), - new Skill("CSS"), - new Skill("JavaScript") - ], - [ - new EmploymentType("Full-time", new Salary(40000, 60000, "USD")), -// new EmploymentType("Part-time", null) - ], - true - ), - new JobOffer( - "4", - "Marketing Specialist", - "XYZ Corporation", - "3+ years", - [ - new Skill("Digital Marketing"), - new Skill("Social Media Management"), - new Skill("Content Creation") - ], - [ - new EmploymentType("Full-time", new Salary(45000, 70000, "USD")), -// new EmploymentType("Freelance", null) - ], - false - ) - ]) - ] - } - - private List getJobs1() { - return [ - new JobOffer( - "1", - "Software Engineer", - "Example Company", - "3+ years", - [ - new Skill("Java"), - new Skill("Python"), - new Skill("SQL") - ], - [ - new EmploymentType("Full-time", new Salary(50000, 80000, "USD")), -// new EmploymentType("Contract", null) - ], - true - ), - new JobOffer( - "2", - "Data Scientist", - "Another Company", - "5+ years", - [ - new Skill("Python"), - new Skill("Machine Learning"), - new Skill("Statistics") - ], - [ - new EmploymentType("Full-time", new Salary(60000, 90000, "USD")) - ], - false - ) - ] - } - - private List getJobs2() { - return [ - new JobOffer( - "1", - "Software Engineer", - "Example Company", - "3+ years", - [ - new Skill("Java"), - new Skill("Python"), - new Skill("SQL") - ], - [ - new EmploymentType("Full-time", new Salary(50000, 80000, "USD")), -// new EmploymentType("Contract", null) - ], - true - ), - new JobOffer( - "2", - "Data Scientist", - "Another Company", - "5+ years", - [ - new Skill("Python"), - new Skill("Machine Learning"), - new Skill("Statistics") - ], - [ - new EmploymentType("Full-time", new Salary(60000, 90000, "USD")) - ], - false - ) - ] + and: + 2 * queue.pub(_) >> {} } + def "should not publish jobs when error occurs"() { + given: + def jobs1 = [JobFixture.jobOffer(), JobFixture.jobOffer()] - class JobBoardImpl implements JobBoard { - private List jobOffers + jobBoard1.getJobs() >> jobs1 + jobBoard2.getJobs() >> { throw new RuntimeException("Test error message") } - JobBoardImpl(List jobOffers) { - this.jobOffers = jobOffers - } + when: + updater.execute() - List getJobs() { - return this.jobOffers - } + then: + thrown(RuntimeException) + 0 * queue.pub(_) >> {} } } \ No newline at end of file From d6bb674228b43a8f9adda45a1e23eae4936e5b10 Mon Sep 17 00:00:00 2001 From: Dawid Stuzynski Date: Fri, 7 Jul 2023 22:03:29 +0200 Subject: [PATCH 5/5] test: Implement test for Publisher --- .../agent/application/PublisherTest.groovy | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 src/test/groovy/it/move2/agent/application/PublisherTest.groovy diff --git a/src/test/groovy/it/move2/agent/application/PublisherTest.groovy b/src/test/groovy/it/move2/agent/application/PublisherTest.groovy new file mode 100644 index 0000000..d45062e --- /dev/null +++ b/src/test/groovy/it/move2/agent/application/PublisherTest.groovy @@ -0,0 +1,36 @@ +package it.move2.agent.application + +import com.fasterxml.jackson.databind.ObjectMapper +import it.move2.agent.configuration.PublisherConfiguration +import it.move2.agent.ports.Queue +import it.move2.job.JobOffer +import spock.lang.Specification +import spock.lang.Subject + +class PublisherTest extends Specification { + + private PublisherConfiguration configuration + private ObjectMapper objectMapper + private Queue queue + + @Subject + Publisher publisher + + def setup() { + configuration = new PublisherConfiguration(2) + objectMapper = new ObjectMapper() + queue = Mock(Queue) + publisher = new Publisher(configuration, objectMapper, queue) + } + + def "publish should chunk job offers and publish them to the queue"() { + given: + List jobOffers = JobFixture.createListJobOffers(10) + + when: + publisher.publish(jobOffers) + + then: + 5 * queue.pub(_) + } +}