Spy, mock, stub in Spock Framework

This commit is contained in:
Kacper Koza 2019-03-03 00:11:21 +01:00
parent 46bad01ab9
commit 01ab66f84f
10 changed files with 278 additions and 2 deletions

View File

@ -48,9 +48,9 @@
</build>
<properties>
<spock-core.version>1.0-groovy-2.4</spock-core.version>
<spock-core.version>1.3-RC1-groovy-2.4</spock-core.version>
<groovy-all.version>2.4.7</groovy-all.version>
<gmavenplus-plugin.version>1.5</gmavenplus-plugin.version>
</properties>
</project>
</project>

View File

@ -0,0 +1,15 @@
package mocks;
public class CharacterCalculator {
public int countCharacterInString(String value, char characterToCount) {
int result = 0;
for (int i = 0; i < value.length(); i++) {
if (value.charAt(i) == characterToCount) {
result++;
}
}
return result;
}
}

View File

@ -0,0 +1,7 @@
package mocks;
public interface EventPublisher {
void publish(String addedOfferId);
}

View File

@ -0,0 +1,5 @@
package mocks;
public class ExternalItemProviderException extends RuntimeException {
}

View File

@ -0,0 +1,36 @@
package mocks;
import java.util.Objects;
public class Item {
private final String id;
private final String name;
public Item(String id, String name) {
this.id = id;
this.name = name;
}
public String getId() {
return id;
}
public String getName() {
return name;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Item item = (Item) o;
return Objects.equals(id, item.id) &&
Objects.equals(name, item.name);
}
@Override
public int hashCode() {
return Objects.hash(id, name);
}
}

View File

@ -0,0 +1,9 @@
package mocks;
import java.util.List;
public interface ItemProvider {
List<Item> getItems(List<String> itemIds);
}

View File

@ -0,0 +1,37 @@
package mocks;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
public class ItemService {
private final ItemProvider itemProvider;
private final EventPublisher eventPublisher;
public ItemService(ItemProvider itemProvider, EventPublisher eventPublisher) {
this.itemProvider = itemProvider;
this.eventPublisher = eventPublisher;
}
List<Item> getAllItemsSortedByName(List<String> itemIds) {
List<Item> items;
try{
items = itemProvider.getItems(itemIds);
} catch (RuntimeException ex) {
throw new ExternalItemProviderException();
}
return items.stream()
.sorted(Comparator.comparing(Item::getName))
.collect(Collectors.toList());
}
void saveItems(List<String> itemIds) {
List<String> notEmptyOfferIds = itemIds.stream()
.filter(itemId -> !itemId.isEmpty())
.collect(Collectors.toList());
// save in database
notEmptyOfferIds.forEach(eventPublisher::publish);
}
}

View File

@ -0,0 +1,10 @@
package mocks;
public class LoggingEventPublisher implements EventPublisher {
@Override
public void publish(String addedOfferId) {
System.out.println("I've published: " + addedOfferId);
}
}

View File

@ -0,0 +1,26 @@
package mocks
import spock.lang.Specification
class ExampleSpockTest extends Specification {
CharacterCalculator characterCalculator
def setup() {
characterCalculator = new CharacterCalculator()
}
def 'should calculate character occurrences in given string'() {
given:
char characterToCount = 'o'
String value = 'Hello world!'
when:
int result = characterCalculator.countCharacterInString(value, characterToCount)
then:
result == 2
}
}

View File

@ -0,0 +1,131 @@
package mocks
import spock.lang.Specification
class ItemServiceTest extends Specification {
ItemProvider itemProvider
ItemService itemService
EventPublisher eventPublisher
def setup() {
itemProvider = Stub(ItemProvider)
eventPublisher = Mock(EventPublisher)
itemService = new ItemService(itemProvider, eventPublisher)
}
def 'should return items sorted by name'() {
given:
def ids = ['offer-id', 'offer-id-2']
itemProvider.getItems(ids) >> [new Item('offer-id-2', 'Zname'), new Item('offer-id', 'Aname')]
when:
List<Item> items = itemService.getAllItemsSortedByName(ids)
then:
items.collect { it.name } == ['Aname', 'Zname']
}
def 'arguments constraints'() {
itemProvider.getItems(['offer-id'])
itemProvider.getItems(_) >> []
itemProvider.getItems(*_) >> []
itemProvider.getItems(!null) >> []
itemProvider.getItems({ it.size > 0 }) >> []
}
def 'should return different items on subsequent call'() {
given:
itemProvider.getItems(_) >>> [
[],
[new Item('1', 'name')],
[new Item('2', 'name')]
]
when: 'method is called for the first time'
List<Item> items = itemService.getAllItemsSortedByName(['not-important'])
then: 'empty list is returned'
items == []
when: 'method is called for the second time'
items = itemService.getAllItemsSortedByName(['not-important'])
then: 'item with id=1 is returned'
items == [new Item('1', 'name')]
when: 'method is called for the thirdtime'
items = itemService.getAllItemsSortedByName(['not-important'])
then: 'item with id=2 is returned'
items == [new Item('2', 'name')]
}
def 'should throw ExternalItemProviderException when ItemProvider fails'() {
given:
itemProvider.getItems(_) >> { new RuntimeException()}
when:
itemService.getAllItemsSortedByName([])
then:
thrown(ExternalItemProviderException)
}
def 'chaining response'() {
itemProvider.getItems(_) >>> { new RuntimeException() } >> new SocketTimeoutException() >> [new Item('id', 'name')]
}
def 'should return different items for different ids lists'() {
given:
def firstIds = ['first']
def secondIds = ['second']
itemProvider.getItems(firstIds) >> [new Item('first', 'Zname')]
itemProvider.getItems(secondIds) >> [new Item('second', 'Aname')]
when:
def firstItems = itemService.getAllItemsSortedByName(firstIds)
def secondItems = itemService.getAllItemsSortedByName(secondIds)
then:
firstItems.first().name == 'Zname'
secondItems.first().name == 'Aname'
}
def 'should publish events about new non-empty saved offers'() {
given:
def offerIds = ['', 'a', 'b']
when:
itemService.saveItems(offerIds)
then:
2 * eventPublisher.publish({ it != null && !it.isEmpty()})
}
def 'should return items'() {
given:
itemProvider = Mock(ItemProvider)
itemProvider.getItems(['item-id']) >> [new Item('item-id', 'name')]
itemService = new ItemService(itemProvider, eventPublisher)
when:
def items = itemService.getAllItemsSortedByName(['item-id'])
then:
items == [new Item('item-id', 'name')]
}
def 'should spy on EventPublisher method call'() {
given:
LoggingEventPublisher eventPublisher = Spy(LoggingEventPublisher)
itemService = new ItemService(itemProvider, eventPublisher)
when:
itemService.saveItems(['item-id'])
then:
1 * eventPublisher.publish('item-id')
}
}