class SomeService{
public String getValue(){
return SomeUtil.generateValue();
}
}
class SomeUtil{
public static String generateValue() {
return "yahoo";
}
}
I want to unit test the SomeService.getValue method.
I am trying the following:
#Test
void "getValue should return whatever util gives"(){
def mockSomeUtil = mock(SomeUtil)
mockSomeUtil.static.generateValue().returns("blah")
play {
Assert.assertEquals(someService.getValue(), "blah")
}
}
But it fails as the util method isn't actually getting mocked.
Question:
How can I unit test my service method?
I made a quick test and it is working without a hassle:
#Grapes([
#Grab(group='org.gmock', module='gmock', version='0.8.3'),
#Grab(group='junit', module='junit', version='4.12')
])
import org.gmock.*
import org.junit.*
import org.junit.runner.*
class SomeService {
public String getValue(){
return SomeUtil.generateValue()
}
}
class SomeUtil {
public static String generateValue() {
return "yahoo"
}
}
#WithGMock
class DemoTest {
def someService = new SomeService()
#Test
void "getValue should return whatever util gives"() {
def mockSomeUtil = mock(SomeUtil)
mockSomeUtil.static.generateValue().returns("blah")
play {
Assert.assertEquals(someService.getValue(), "blah")
}
}
}
def result = JUnitCore.runClasses(DemoTest.class)
assert result.failures.size() == 0
If you need to invoke the service several times, you may need a stub, i.e.:
mockSomeUtil.static.generateValue().returns("blah").stub()
Related
Let's say if I have a test that uses builders to construct objects. The problem is that the builder() method in the builder class is static.
Generally, mocking a static method is already an indicator of bad design. However, in the case of builders, the builder() methods are always static. What's the best approach to unit testing methods using builders()? Should the builders be refactored into a separate class to facilitate mocking?
class Service {
private SqsClient sqsClient;
private String sqsQueueUrl;
public Service(String sqsQueueUrl) {
this.sqsClient = SqsClient.builder().build();
this.sqsQueueUrl = sqsQueueUrl;
}
public SqsClient getClient() {
return this.client;
}
public SqsClient setClient(SqsClient client) {
this.client = client;
}
public String getSqsQueueUrl() {
return this.sqsQueueUrl;
}
public void setSqsQueueUrl(String sqsQueueUrl) {
this.sqsQueueUrl = sqsQueueUrl;
}
public void onEvent(Activity activity) {
// How to mock builders in unit test?
DeleteMessageRequest deleteRequest = DeleteMessageRequest.builder().queueUrl(this.sqsQueueUrl).receiptHandle(activity.getReceiptHandle()).build();
DeleteMessageResponse deleteMessageResponse = this.sqsClient.deleteMessage(deleteRequest);
}
}
class ServiceTest {
#Test
public void testEvent() {
String sqsQueueUrl = "http://127.0.0.1";
String receiptHandle = "asdasd";
SqsClient sqsClient = EasyMock.mock(SqsClient.class);
Service service = EasyMock.mock(Service.class);
// EasyMock expect and replay here.
service.setClient(sqsClient);
service.setSqsQueueUrl(sqsQueueUrl);
Activity activity1 = new Activity();
activity.setReceiptHandle(receiptHandle);
service.onEvent(activity);
}
}
I'm having trouble understanding why all those processors pass the test but Behavior does not:
package com.example;
import org.junit.Test;
import io.reactivex.Flowable;
import io.reactivex.processors.*;
public class ProcessorTest {
private static Flowable<String> justFoo() {
return Flowable.just("foo");
}
private static FlowableProcessor<String> subscribeToFoo(
FlowableProcessor<String> processor) {
justFoo().subscribe(processor);
return processor;
}
#Test public void flowable() { // pass
justFoo().test().assertValue("foo");
}
#Test public void async() { // pass
subscribeToFoo(AsyncProcessor.create()).test().assertValue("foo");
}
#Test public void replay() { // pass
subscribeToFoo(ReplayProcessor.create()).test().assertValue("foo");
}
#Test public void unicast() { // pass
subscribeToFoo(UnicastProcessor.create()).test().assertValue("foo");
}
#Test public void behaviorFail() { // fail
subscribeToFoo(BehaviorProcessor.create()).test().assertValue("foo");
}
#Test public void behaviorPassing() { // pass
subscribeToFoo(BehaviorProcessor.create())
.test()
.assertNoValues()
.assertSubscribed()
.assertComplete()
.assertNoErrors()
.assertNoTimeout()
.assertTerminated();
}
}
The docs say that BehaviorProcessor is a:
Processor that emits the most recent item it has observed and all subsequent observed items to each subscribed Subscriber.
So in my understanding it should pass the behaviorFail test, not the behaviorPassing. How come is that?
How would I write a valid test, to know that a BehaviorProcessor emitted a certain value?
Getting rid of the terminal event passed to the processor would help:
#Test public void behavior() {
final BehaviorProcessor<String> processor = BehaviorProcessor.create();
justFoo().concatWith(Flowable.never()).subscribe(processor);
processor.test().assertValue("foo");
}
Tested class:
public class ClassForTest {
public String hello(){
return "hello " + getClassName();
}
public String getClassName(){
return ClassForTest.class.getName();
}
}
Spock class:
class ClassForSpockTest extends Specification{
def setupSpec(){
ClassForTest.metaClass.getClassName={"ClassForSpockTest"}
}
def "override test"(){
setup:
ClassForTest cft = new ClassForTest()
expect:
cft.getClassName() == "ClassForSpockTest"
}
def "mock test"(){
setup:
ClassForTest cft = new ClassForTest()
expect:
cft.hello() == "hello ClassForSpockTest"
}
}
override test test is passed!
Mock test is crashing, cft.hello() return "hello ClassForTest"
You can't use the metaclass to override a method call in a Java class from another method in that class. This is a limitation of spock, Java, and groovy. In this case, you have to use other mocking techniques. For example, you can use subclassing:
setup:
ClassForTest cft = new ClassForTest() {
String getClassName() {"ClassForSpockTest"}
}
How can I stub/mock a void method which populates some objects that would be used later.
class RequestHelper{
public void populateOrderRequestBody(String product,String quantity,String profile, OrderType orderType){
orderType.setProduct(product);
orderType.setQuantity(Integer.parseInt(quantity));
orderType.setUser(profile.getUserId());
} }
class ServiceClient{
RequestHelper rh;
public void docall(Order order){
OrderType orderType = FACTORY.CreateOrderType;
rh.populateOrderRequestBody(order.getProduct(),order.getQuantity(),order.getProfile(),orderType);
/**
* some other code
**/
}
public setRequestHelper(RequestHelper rh){
this.rh=rh;
}
public RequestHelper getRequestHelper(){
return this.rh;
}}
Now I want to test ServiceClient class which call RequestHelper to populate orderType object. How to stub the method of RequestHelper class.
In this particular case if no verification will be done to rh filed you just need a plain Stub - just to ensure no NullPointerException is thrown when testing the docall method. Mock will also be sufficient however is more advanced object and using it here is pointless. When it comes to Spy it's used to verify invocations on a real (in terms of not being mocked) object. Have a look at the example below - runs smoothly just with Stub:
#Grab('org.spockframework:spock-core:1.0-groovy-2.4')
#Grab('cglib:cglib-nodep:3.1')
import spock.lang.*
class Test extends Specification {
def 'spec'() {
given:
def service = new ServiceClient()
service.rh = Mock(RequestHelper)
when:
service.doCall(new Order())
then:
noExceptionThrown()
}
}
class Order {
String product
String quantity
String profile
}
class OrderType { }
class FACTORY {
static OrderType CreateOrderType = new OrderType()
}
class RequestHelper {
public void populateOrderRequestBody(String product, String quantity, String profile, OrderType orderType) {
orderType.setProduct(product);
orderType.setQuantity(Integer.parseInt(quantity));
orderType.setUser(profile.getUserId());
}
}
class ServiceClient {
RequestHelper rh;
public void doCall(Order order) {
OrderType orderType = FACTORY.CreateOrderType;
rh.populateOrderRequestBody(order.getProduct(), order.getQuantity(), order.getProfile(), orderType);
}
public setRequestHelper(RequestHelper rh){
this.rh=rh;
}
public RequestHelper getRequestHelper(){
return this.rh;
}
}
Very similar to Opal's answer but using a mock order..
class Test extends Specification {
def 'spec'() {
given:
def service = new ServiceClient()
def order = Mock(Order)
order.getProduct() >> 'product1'
order.getProfile() >> 'profile1'
order.getQuantity() >> 3
service.rh = Mock(RequestHelper)
when:
service.doCall(order)
then:
noExceptionThrown()
1 * rh.populateOrderRequestBody('product1',3,'profile1',FACTORY.CreateOrderType)
}
}
Note that this only works if the CreateOrderType.equals() will return true
I want to use Guice and GuiceBerry to inject a non-static legacy service into a factory class. I then want to inject that factory into my Parameterized JUnit test.
However, the issue is JUnit requires that the #Parameters method be static.
Example factory:
#Singleton
public class Ratings {
#Inject
private RatingService ratingService;
public Rating classicRating() {
return ratingService.getRatingById(1002)
}
// More rating factory methods
}
Example test usage:
#RunWith(Parameterized.class)
public class StaticInjectParamsTest {
#Rule
public GuiceBerryRule guiceBerryRule = new GuiceBerryRule(ExtendedTestMod.class)
#Inject
private static Ratings ratings;
#Parameter
public Rating rating;
#Parameters
public static Collection<Rating[]> ratingsParameters() {
return Arrays.asList(new Rating[][]{
{ratings.classicRating()}
// All the other ratings
});
}
#Test
public void shouldWork() {
//Use the rating in a test
}
}
I've tried requesting static injection for the factory method but the Parameters method gets called before the GuiceBerry #Rule. I've also considered using just the rating's Id as the parameters but I want to find a reusable solution. Maybe my approach is flawed?
Unfortunately, JUnit needs to be able to enumerate all of the tests before running any tests, so the parameters method must be called before rules.
You could define an enum for the type of rating:
#RunWith(Parameterized.class)
public class StaticInjectParamsTest {
#Rule
public GuiceBerryRule guiceBerryRule
= new GuiceBerryRule(ExtendedTestMod.class);
#Inject
private Ratings ratings;
#Parameter
public RatingType ratingType;
#Parameters
public static Collection<RatingType> types() {
return Arrays.asList(RatingType.values());
}
#Test
public void shouldWork() {
Rating rating = ratings.get(ratingType);
// Use the rating in a test
}
}
Edit: Code for enum:
public enum RatingType {
CLASSIC(1002),
COMPLEX(1020);
private final int ratingId;
private RatingType(int ratingId) {
this.ratingId = ratingId;
}
// option 1: keep rating ID private by having a method like this
public get(RatingService ratingService) {
return ratingService.getRatingById(ratingId);
}
// option 2: have a package-scope accessor
int getRatingId() {
return ratingId;
}
}
Edit: if you go with option 2 you would then add a new method to get a Rating from a RatingType which would delegate to the service passing ratingId:
#Singleton
public class Ratings {
#Inject
private RatingService ratingService;
public Rating getRating(RatingType ratingType) {
return ratingService.getRatingById(
ratingType.getRatingId());
}
// More rating factory methods
}
If you don't want RatingType to be in your public API, you can define it in your test, and have a method in the enum named getRating()
public enum RatingType {
CLASSIC {
#Override public Rating getRating(Ratings ratings) {
return ratings.getClassicRating();
}
},
COMPLEX {
#Override public Rating getRating(Ratings ratings) {
return ratings.getComplexRating();
}
};
public abstract Rating getRating(Ratings ratings);
}
You could also create a value type instead of an enum.
This assumes you can write tests that should pass for all Rating instances.
If you have some common tests but some rating-specific tests, I would make an abstract base class that contains common tests, and an abstract createRating() method, and subclass it for every rating type.
My solution was to add a RatingId class that wraps an integer and create a factory RatingIds that I could then return static and use as parameters. I overloaded the getRatingById method in my RatingService interface to accept the new RatingId type, and then inject the rating service into my test and use it directly.
Added factory:
public class RatingIds {
public static RatingId classic() {
return new RatingId(1002);
}
// Many more
}
Test:
#RunWith(Parameterized.class)
public class StaticInjectParamsTest {
#Rule
public GuiceBerryRule guiceBerryRule = new GuiceBerryRule(ExtendedTestMod.class)
#Inject
private RatingService ratingService
#Parameter
public RatingId ratingId;
#Parameters
public static Collection<RatingId[]> ratingsParameters() {
return Arrays.asList(new RatingId[][]{
{RatingIds.classic()}
// All the other ratings
});
}
#Test
public void shouldWork() {
Rating rating = ratingService.getRatingById(ratingId.getValue())
//Use the rating in a test
}
}
In cases as yours, where the total number of generated parameter sets is known in advance, but building the parameters itself requires some context (e.g. autowired service instance with Spring) you can go the functional approach (with junit5 & parameterized)
Obviously that does not work, if the createParameter function itself depends on such contex:-/
class MyTestClass {
// may be autowired, cannot be static but is required in parameter generation
SomeInstance instance;
private interface SomeParamBuilder { SomeParam build(SomeInstance i);}
private static Stream<Arguments> createParamterFactories() {
return Stream.of(
Arguments.of((SomeParamBuilder)(i)->
{
return new SomeParam(i);
})
);
}
// does not work, because SomeParam needs SomeInstance for construction
// which is not available in static context of createParameters.
//#ParameterizedTest(name = "[{index}] {0}")
//#MethodSource("createParameters")
//void myTest(SomeParam param) {
//}
#ParameterizedTest(name = "[{index}] {0}")
#MethodSource("createParamterFactories")
void myTest(SomeParamBuilder builder) {
SomeParam param = builder.build(instance);
// rest of your test code can use param.
}
}
maven dep:
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-params</artifactId>
<version>5.2.0</version>
<scope>test</scope>
</dependency>
I did not get guiceberry to run (ancient dependencies), but using JUnitParamters and plain guice, this is rather simple:
#RunWith(JUnitParamsRunner.class)
public class GuiceJunitParamsTest {
public static class SquareService {
public int calculate(int num) {
return num * num;
}
}
#Inject
private SquareService squareService;
#Before
public void setUp() {
Guice.createInjector().injectMembers(this);
}
#Test
#Parameters({ "1,1", "2,4", "5,25" })
public void calculateSquares(int num, int result) throws Exception {
assertThat(squareService.calculate(num), is(result));
}
}
If you check the JUnitParams website, you will find a lot of other ways to define the parameters list. It is really easy to do this with the injecte service.