I have a very simple class as shown
class MyClass {
public static String getName(String input)
{
return toUpperCase(input);
}
public static String toUpperCase(String name)
{
return name.toUpperCase();
}
}
To test the above I have written a Test Case using Spock FW as shown below:
class MyClassTest extends Specification{
def 'check uppercase scnario'() {
given:
MyClass myClass = new MyClass();
when:
myClass.getName("test")
then: ""
1*myClass.toUpperCase("test");
}
}
But when I run this I see 0 Interactions
You cannot verify interactions on static Java methods. Just make your methods non-static. Besides, in the given: block, you are instantiating the class, so I guess you want to use instance methods anyway.
class MyClass {
public String getName(String input) {
return toUpperCase(input);
}
public String toUpperCase(String name) {
return name.toUpperCase();
}
}
Furthermore, if you wish to verify interactions on self-invocation calls, a Mock() is not what you need. Instead, simply use a Spy():
class MyClassTest extends Specification {
def 'check uppercase scnario'() {
given:
MyClass myClass = Spy()
when:
myClass.getName("test")
then:
1 * myClass.toUpperCase("test");
}
}
Try it in the Groovy Web Console.
Related
I am writing a payment service class in Dart that wraps more than 1 payment provider. The expectation is the caller can simply switch one to another without any hassle.
Let's imagine I have classes like this:
enum PaymentProvider { providerA, providerB }
abstract class PaymentService {
void processPayment(Order oder);
}
class PaymentServiceA implements PaymentService {
final String appKey;
final String merchantId;
PaymentServiceA(this.appKey, this.merchantId);
#override
void processPayment(Order oder) {
// concrete implementation to process payment
}
String getVoucher() {
// return voucher code
}
}
class PaymentServiceB implements PaymentService {
final PaymentBOptions options;
PaymentServiceB(this.options);
#override
void processPayment(Order oder) {
// concrete implementation to process payment
}
List<PaymentBHistory> getPaymentHistory() {
// return payment history
}
}
class PaymentBOptions {
final bool sendEmailReceipt;
final Function()? successCallback;
PaymentBOptions(this.sendEmailReceipt, this.successCallback);
}
So here PaymentServiceA and PaymentServiceB have same method (processPayment) so we can create base class PaymentService and let them implements this base class.
However as you can see each of them also has different constructor parameter and specific methods.
How is the best approach to create PaymentService that wrap more than 1 provider like this?
I was trying to use factory pattern like this:
abstract class PaymentService {
factory PaymentService(PaymentProvider provider) {
switch(provider) {
case PaymentProvider.providerA:
String appKey = "xxxx";
String merchantId = "123"
return PaymentServiceA(appKey, merchantId);
case PaymentProvider.providerB:
PaymentBOptions options = PaymentBOptions(() {
});
return PaymentServiceB(options);
}
}
void processPayment(Order order);
}
But I don't think this is the good practice because:
If we create PaymentServiceA or PaymentServiceB instance using PaymentService factory method it will return as PaymentService and we need to cast to appropriate class in order to access specific PaymentService method.
We can't supply specific constructor parameter of PaymentServiceA or PaymentServiceB outside PaymentService abstract class via factory constructor.
Any idea on how is the best practice and what's the suitable design pattern when facing this kind of scenario?
Thanks.
I used PowerMock to Mock Constructor.Afer launching the application,I thought all lines shoud be green.However,actually all lines are red.
I think Mocking Constructor results in this phenomenon.Beacause mocking others,like final classes, is OK.How to fix this problem?
//code:
public class People {
public String sayHello(){
return "hello";
}
}
public class Family {
public String doEvent() {
People p = new People();
String str = p.sayHello();
System.out.println(str);
return str;
}
}
#RunWith(PowerMockRunner.class)
#PrepareForTest(Family.class)
public class FamilyTest {
#Test
public void test() throws Exception {
Family f = new Family();
String str = "hello mock";
People p = PowerMock.createMock(People.class);
PowerMock.expectNew(People.class).andReturn(p);
EasyMock.expect(p.sayHello()).andReturn(str);
PowerMock.replay(p, People.class);
String strActual = f.doEvent();
Assert.assertEquals(str, strActual);
PowerMock.verify(p, People.class);
}
}
You shouldn't have to use #PrepareForTest unless you are mocking static methods inside that class.
I believe your issue is that when you prepare a class for test using Powermocks runner, it does something funky with the byte code, which EclEmma uses for line coverage. Since you are not mocking any static methods in your family class, try removing that from your #PrepareForTest.
The error was on integration test of a service. Yes, we're currently doing integration test on our service as a workaround since we cannot test the services via unit test due to userType mapping.
Regarding userType: Our Domain uses interface as properties. In addition findByinterface won't work on grails.
see below:
class Domain {
SomeProperty someProperty
String otherProperty
}
public interface SomeProperty {
//methods
}
enum Enum implements SomeProperty {
NAME,
OTHERNAME
//implementation of methods
}
class Domain can handle different kinds of enum implementing the SomeProperty inteface.
Database won't know what particular value should it saved so we go with the userType. below is the Domain with the mapping
class Domain {
SomeProperty someProperty
String otherProperty
}
static mapping = {
id generator: 'sequence', column: 'id', params: [sequence: 'domain_sequence']
someProperty type : userType, {
column name: "someProperty", sqlType: "varchar", length: 255
}
}
Updated:
Code being tested:
class ServiceBeingTested {
AnotherServiceInsideServiceBeingTested anotherServiceInsideServiceBeingTested //or def anotherServiceInsideServiceBeingTested
public void methodBeingTested(param1, param2, param3) {
Object object = privateMethod(..., ...) //private method contains no other service calls. just pure logic
anotherServiceInsideServiceBeingTested.voidMethod1(....)
anotherServiceInsideServiceBeingTested.voidMethod2(....)
}
}
My integration test:
class ServiceBeingTestedIntegrationSpec extends IntegrationSpec {
ServiceBeingTested serviceBeingTested = new ServiceBeingTested()
AnotherServiceInsideServiceBeingTested anotherServiceInsideServiceBeingTested
void setUp () {
anotherServiceInsideServiceBeingTested = Mock()
serviceBeingTested.anotherServiceInsideServiceBeingTested = anotherServiceInsideServiceBeingTested
}
void cleanup () {
//code here
}
void "methodBeingTested should invoke the 2 service method call"() {
given:
//initialize data here
//code
when:
serviceBeingTested.methodBeingTested(param1, param2, param3)
then:
1 * anotherServiceInsideServiceBeingTested.voidMethod1(....)
1 * anotherServiceInsideServiceBeingTested.voidMethod2(....)
}
}
StackTrace:
| Too few invocations for:
1 * anotherServiceInsideServiceBeingTested.voidMethod2(....) (0 invocations)
Unmatched invocations (ordered by similarity):
1 * anotherServiceInsideServiceBeingTested.this$3$voidMethod2(....)
The other service call with same anotherServiceInsideServiceBeingTested -i.e anotherServiceInsideServiceBeingTested.voidMethod1 was correctly invoked. I tried changing the parameters in test for voidMethod2 to wildcards but will still result to this error.
Thanks
In integration test cases, you don't need to mock any of the services as these are available by default as the full application is loaded.
Though, in unit test, you may use #TestFor annotation and specify the service which you want to test, this will inject a service variable which would be available through you specification / test class.
#TestFor(Service)
class ServiceBeingTestedIntegrationSpec extends Specification {
ServiceBeingTested serviceBeingTested = new ServiceBeingTested()
void setUp () {
serviceBeingTested.service = service
}
void cleanup () {
//code here
}
void "methodBeingTested should invoke the 2 service method call"() {
given:
//initialize data here
//code
when:
serviceBeingTested.methodBeingTested(param1, param2, param3)
then:
1 * service.voidMethod1(....)
1 * service.voidMethod2(....)
}
}
Also, in case above you could also try to stub your methods in setup after mocking these to avoid any other service called by your service which will throw NullPointerException and eventually your test would fail in case of unit tests.
example of stubbing could be:
1*service.voidMethod1 >> {
//some code setting up any data for you.
}
1*service.voidMethod2 >> {
//some code setting up any data for you.
}
If you use stubbing like above you can simply write down unit test cases as well.
I have a few tests that are very similar in my Grails integration test suite (which uses Spock). I want to have a base test class which has the 90% of the common logic of the tests and then let test classes extend from it.
I was thinking:
public abstract BaseSpecification extends IntegrationSpec {
public baseTest() {
//
setUp:
//
...
when:
//
...
then:
...
}
}
and then:
public class SpecificTestSpecification extends BaseSpecification {
public baseTest() {
setup:
// more set up
super.baseTest();
when:
// some more specific testing
then:
// som more testing
}
}
But trying this I get two issues:
It runs both BaseClass and SpecificationClass
When the SpecificationClass runs, it fails on:
groovy.lang.MissingMethodException: No signature of method: BaseSpecification.baseTest() is applicable for argument types: () values: []
Possible solutions: any(), old(java.lang.Object), any(groovy.lang.Closure), notify(), wait(), Spy()
at
Any ideas how I can achieve inheritance in my spock integration tests?
I don't know if it can be done with Spock. When I tried I couln't find a way to reuse spock statements and what I did was to write a BaseSpecification class with utility methods that can be used inside spock statements.
This is an example test.
#TestFor(Address)
class AddressSpec extends BaseSpecification {
...
void "Country code should be 3 chars length"(){
when:
domain.countryCode = countryCode
then:
validateField('countryCode', isValid, 'minSize.notmet')
where:
[countryCode, isValid] << getMinSizeParams(3)
}
And the BaseSpecification class
class BaseSpecification extends Specification {
// Return params that can be asigned in `where` statement
def getMinSizeParams(Integer size){[
[RandomStringUtils.randomAlphabetic(size - 1), false],
[RandomStringUtils.randomAlphabetic(size), true]
]}
// Make an assetion, so it can be used inside `then` statement
protected void validateField(String field, String code, Boolean shouldBeValid){
domain.validate([field])
if(shouldBeValid)
assert domain.errors[field]?.code != code
else
assert domain.errors[field]?.code == code
}
}
It's an unit test but I think it should work with Integration tests too.
Okay, now I got your point.
You can pretty much use like this:
class BaseSpecification extends IntegrationSpec {
//User userInstance
def setup() {
// do your common stuff here like initialize a common user which is used everywhere
}
def cleanup() {
}
}
class SpecificTestSpecification extends BaseSpecification {
def setup() {
// specific setup here. Will call the super setup automatically
}
def cleanup() {
}
void "test something now"() {
// You can use that userInstance from super class here if defined.
}
}
I have a grails-plugin called "listadmin" there is a domain model "Liste":
package listadmin
class Liste {
String internal_name
String public_name
Boolean edtiable = true
Boolean visible = true
static hasMany = [eintrage : ListenEintrag]
static constraints = {
internal_name(unique : true , blank : false);
}
String toString() {
"${public_name}"
}
}
I have service called "SECO_ListenService" in the same module (grails-plugin):
package listadmin
class SECO_ListenService {
def getEntriesOfList(String intnalListName) {
def aList = Liste.findByInternal_name(intnalListName)
return aList
}
}
Now I try to call this service from an other module (grails-plugin) called "institutionadmin". The SECO_ListenService should return a list of strings for an select of a domain model in the inistitutionadmin:
package institutionadmin
import listadmin.SECO_ListenService
class Einrichtung {
Long einrichtungs_type
Long type_of_conzept
int anzahl_gruppen
int anzahl_kinder_pro_Gruppe
String offnungszeiten
static hasMany = [rooms : Raum]
static constraints = {
def aList = []
def sECO_ListenService = new SECO_ListenService()
aList=sECO_ListenService.getEntriesOfList("einrichtung_type")
einrichtungs_type(inList: aList)
}
}
If I try to run this application with the both modules. I get the following error:
Caused by MissingMethodException: No signature of method:
listadmin.Liste.methodMissing() is applicable for argument types: ()
values: []
It seemed to be that the service class don't know the "Liste"-domain-model. But I don't know where the error is. I also tried to call other standard methods like "findAll" but without any success.
Has anybody an idea where my mistake could be?
To get a service in a static context you need to access the grailsApplication spring bean. This can be done thought Holders. Example:
class MyService {
List<String> getAvailable() {
return ['A','B','C']
}
}
class MyDomainClass {
String something
static constraints = {
something inList: getSomethingList()
}
static List<String> getSomethingList() {
def myService = Holders.grailsApplication.mainContext.getBean('myService')
return myService.getAvailable()
}
}