I am using Hystrix to improve my services. How can I decapsulate the service calls into Hystrix. I know you can create for each call a special hystrix-class, but this would be too much work without using Spring!
I try to describe my problem with pseudocode:
public class HystrixController extends HystrixCommand {
public static void main(String[] args) throws Exception {
HystrixController hystrixController = new HystrixController();
System.out.print(hystrixController.execute());
}
private final ExampleService exampleService;
protected HystrixController() throws Exception {
super(HystrixCommandGroupKey.Factory.asKey("ExampleGroup"));
this.exampleService = new ExampleService();
}
// Call 1
public List getItemsAsList() {
return exampleService.getItemsByContractId(contractID);
}
// Call 2
public List getItemsByName() {
return exampleService.getItemsByName(contractID);
}
// How can I isolate the two calls ? The run() only allows me to use one.
#Override
protected List run() throws Exception {
return getItemsAsList();
}
}
In the example you can see it is only possible to execute only one call. I would like to have something like that:
public class HystrixController extends HystrixCommand {
public static void main(String[] args) throws Exception {
HystrixController hystrixController = new HystrixController();
System.out.print(hystrixController.execute(1));
System.out.print(hystrixController.execute(2));
}
private final ExampleService exampleService;
protected HystrixController() throws Exception {
super(HystrixCommandGroupKey.Factory.asKey("ExampleGroup"));
this.exampleService = new ExampleService();
}
// Call 1
public List getItemsAsList() {
return exampleService.getItemsByContractId(contractID);
}
// Call 2
public List getItemsByName() {
return exampleService.getItemsByName(contractID);
}
// Multi Threads
#Override
protected List run_getItemsAsList() throws Exception {
return getItemsAsList();
}
#Override
protected List run_getItemsByName() throws Exception {
return getItemsByName();
}
}
Thanks you in advance and I am sorry for my broken English
Related
I trying to test the camel output as Object but which fails to get exchange object.This is where it fails Customer resultCustomer = processActs.getExchanges().get(0).getIn().getBody(Customer.class). Please help me to solve this.I referred this Right way to test my object in Camel
Customer POJO:
public class Customer {
private String firstName;
private String lastName;
// getters and setters
#Override
public String toString(){
return firstName +":::" + lastName;
}
}
Test Route:
public class FileTest4 extends CamelTestSupport {
#EndpointInject(uri = "direct:teststart")
private Endpoint start;
#EndpointInject(uri = "mock:direct:processActs")
private MockEndpoint processActs;
#EndpointInject(uri = "mock:direct:write2File")
private MockEndpoint write2File;
#EndpointInject(uri = "mock:end")
private MockEndpoint mockEndResult;
#Override
public boolean isUseAdviceWith() {
return true;
}
#Override
protected RouteBuilder createRouteBuilder() throws Exception {
return new RouteBuilder() {
#Override
public void configure() throws Exception {
from("file:/var/file.log&noop=true").routeId("MY_ROUTE").to("direct:processActs");
from("direct:processActs").process(exchange -> {
List<Customer> customers = new ArrayList<>();
customers.add(new Customer("F1", "L1"));
customers.add(new Customer("F2", "L2"));
customers.add(new Customer("F3", "L3"));
exchange.getOut().setBody(customers);
}).to("direct:write2File");
from("direct:write2File").split(simple("${body}")).log("Content: ${body}");
}
};
}
#Override
protected void doPostSetup() throws Exception {
context.getRouteDefinition("MY_ROUTE").adviceWith(context, new AdviceWithRouteBuilder() {
#Override
public void configure() throws Exception {
replaceFromWith("direct:teststart");
weaveAddLast().to("mock:end");
}
});
context.start();
}
#Test
public void testUnmarshal() throws Exception {
mockEndResult.expectedMessageCount(1);
// ArrayIndex Exception here exchanges list is empty
Customer resultCustomer = processActs.getExchanges().get(0).getIn().getBody(Customer.class);
assertEquals(resultCustomer.toString(),"F1:::L1");
write2File.expectedBodiesReceived("F1:::L1", "F3:::L3", "F2:::L2");
template.sendBody("direct:teststart", new File("src/test/resources/test.txt"));
mockEndResult.assertIsSatisfied();
}
}
It looks like you're inspecting the mock endpoint before you've actually sent any exchanges. Try moving the check to the end of the test, e.g.:
#Test
public void testUnmarshal() throws Exception {
mockEndResult.expectedMessageCount(1);
write2File.expectedBodiesReceived("F1:::L1", "F3:::L3", "F2:::L2");
template.sendBody("direct:teststart", new File("src/test/resources/test.txt"));
mockEndResult.assertIsSatisfied();
Customer resultCustomer = processActs.getExchanges().get(0).getIn().getBody(Customer.class);
assertEquals(resultCustomer.toString(),"F1:::L1");
}
UPDATE
On closer inspection, I think you've got your mocks muddled up. Judging by the assertions you want to check that three customers are written out. However your mocks aren't set up for this.
mock:end is added to the end of MY_ROUTE but that will only ever see the entire customer list returned by the processor in direct:processActs
Also the mocks you declare with #EndpointInject don't get involved in the route because you don't actually mock the real endpoints. You can remove all of them apart from mockEndResult.
The following test does pass.
#Test
public void testUnmarshal() throws Exception {
mockEndResult.expectedMessageCount(1);
template.sendBody("direct:teststart", new File("src/test/resources/test.txt"));
mockEndResult.assertIsSatisfied();
#SuppressWarnings("unchecked")
List<Customer> customers = mockEndResult.getExchanges().get(0).getIn().getBody(List.class);
assertEquals(customers.get(0).toString(), "F1:::L1");
assertEquals(customers.get(1).toString(), "F2:::L2");
assertEquals(customers.get(2).toString(), "F3:::L3");
}
That might not be what you want to test, though. Instead you could weave the mock endpoint in to the splitter, then you'd be able to assert individual customers.
#Override
protected void doPostSetup() throws Exception {
context.getRouteDefinition("MY_ROUTE").adviceWith(context, new AdviceWithRouteBuilder() {
#Override
public void configure() throws Exception {
replaceFromWith("direct:teststart");
}
});
// give direct:write2File the id 'splitter' to be able to advice it
context.getRouteDefinition("splitter").adviceWith(context, new AdviceWithRouteBuilder() {
#Override
public void configure() throws Exception {
weaveByType(LogDefinition.class).after().to("mock:end");
}
});
context.start();
}
#Test
public void testUnmarshal() throws Exception {
mockEndResult.expectedMessageCount(3);
mockEndResult.expectedBodiesReceived("F1:::L1", "F2:::L2", "F3:::L3");
template.sendBody("direct:teststart", new File("src/test/resources/test.txt"));
mockEndResult.assertIsSatisfied();
}
Jmockit is very powerful, but sometimes I cannot understand what it does behind the scene, so I have a question regarding jmockit. Hopefully the more experienced programmers on here could help shine some light on this situation :)
I have the following two classes in two separate files:
public class SmallClass {
String a;
SmallClass(String arg) throws Exception {
a = arg;
}
public String getString() {
return a;
}
}
And
public class BigClass {
private static final SmallClass smallClass;
static {
try {
smallClass = new SmallClass("dummy");
} catch (Exception e) {
throw new IllegalStateException("Could not initialized", e);
}
}
public static String getString() {
return smallClass.getString();
}
}
Now, I have a class to test BigClass:
public class BigClassTest {
#Test
public void testGet() throws Exception {
///CLOVER:OFF
new MockUp<SmallClass>() {
#Mock
public void $init(String string) throws Exception {
//Do nothing
}
#Mock
public String getString() {
return "dummyString";
}
};
///CLOVER:ON
Assert.assertEquals("dummyString", BigClass.getString());
}
#Test(expected = ExceptionInInitializerError.class)
public void testException() throws Exception {
///CLOVER:OFF
new MockUp<SmallClass>() {
#Mock
public void $init(String string) throws Exception{
throw new Exception("Mocked Exception");
}
};
///CLOVER:ON
BigClass.getString();
}
}
If I run each of these independently, then they each passes. But if I run the whole test file, then the first test fails with:
java.lang.NoClassDefFoundError: Could not initialize class BigClass
I also tried tearing down the mock after each test like this, but it doesn't help:
public class BigClassTest {
MockUp<SmallClass> smallClassMockUp;
#Test
public void testGet() throws Exception {
///CLOVER:OFF
smallClassMockUp = new MockUp<SmallClass>() {
#Mock
public void $init(String string) throws Exception {
//Do nothing
}
#Mock
public String getString() {
return "dummyString";
}
};
///CLOVER:ON
Assert.assertEquals("dummyString", BigClass.getString());
smallClassMockUp.tearDown();
}
#Test(expected = ExceptionInInitializerError.class)
public void testException() throws Exception {
///CLOVER:OFF
smallClassMockUp = new MockUp<SmallClass>() {
#Mock
public void $init(String string) throws Exception{
throw new Exception("Mocked Exception");
}
};
///CLOVER:ON
BigClass.getString();
smallClassMockUp.tearDown();
}
}
Any help would be appreciated. Thank you in advance!
The occurrence of NoClassDefFoundError, in a case like this, is not because the class wasn't found by the JVM (it was), but because its static initialization has failed (by throwing an exception or error from the execution of a static initializer). Once this happens, the class is left in an invalid/uninitialized state and cannot be used in the same JVM instance anymore.
For reference, see the "Initialization of classes and interfaces" section in the JLS.
Also, note that the order in which tests execute is not necessarily the textual order they appear in the test class. Here, testException (the second test) runs first. So, when testGet runs, the class is invalid and the JVM throws the error.
before refactor:
public interface Service {
public void hello(Person p);
}
public class BlackPersonServiceImpl implements Service {
#Override
public void hello(Person p) {
//...
}
}
public class WhitePersonServiceImpl implements Service {
#Override
public void hello(Person p) {
//...
}
}
public class BeforeRefactor {
public static void main(String[] args) {
String str = args[0];
Person p = JSON.parseObject(str, Person.class);
Service service = getServiceFromSpringContainer();
service.hello(p);
}
private static Service getServiceFromSpringContainer() {
//...
return null;
}
}
after refactor:
public interface Service {
public void hello(String str);
}
public class WhitePersonServiceImpl implements Service {
#Override
public void hello(String str) {
Person person = JSON.parseObject(str, Person.class);
//do something to person...
//...
}
}
public class AfterRefactor {
public static void main(String[] args) {
String str = args[0];
Service service = getServiceFromSpringContainer();
service.hello(str);
}
private static Service getServiceFromSpringContainer() {
//...
return null;
}
}
That's what I want(I think "pull down" is not the "right" word to describe it...).
I tried "introduce parameter object" in eclipse, and it does not work.
There are many implementations of "Service". I dont want to change them one by one.
Is there a good way to solve this problem?
Thanks!
You can do it somewhat for a single class and a single method (although it's akward and a succession of small refactoring steps), but not across several types at the same time.
I am trying to use Google ThreadWeaver to write a unit test for concurrent code. No matter what I do, I will get an IllegalArgumentException. I am still working with an example, but even that does not work. This is what I tried:
public class ExampleTest {
public static class ExampleMain implements MainRunnable<Example> {
private Example example;
#Override
public Class<Example> getClassUnderTest() {
return Example.class;
}
#Override
public String getMethodName() {
return null;
}
#Override
public Method getMethod() throws NoSuchMethodException {
return null;
}
#Override
public void initialize() throws Exception {
example = new Example();
}
#Override
public Example getMainObject() {
return example;
}
#Override
public void terminate() throws Exception {
}
#Override
public void run() throws Exception {
example.test("second");
}
}
public static class ExampleSecondary implements SecondaryRunnable<Example, ExampleMain> {
private ExampleMain exampleMain;
#Override
public void initialize(ExampleMain main) throws Exception {
exampleMain = main;
}
#Override
public void terminate() throws Exception {
}
#Override
public boolean canBlock() {
return false;
}
#Override
public void run() throws Exception {
exampleMain.getMainObject().test("main");
}
}
public static class Example {
private List<String> list = new ArrayList<String>();
public String test(String s) {
System.out.println("1" + s);
list.add(s);
System.out.println("2" + s);
return list.get(0);
}
}
#Test
public void testThreadWeaver() throws Exception {
ClassInstrumentation instrumentation = Instrumentation.getClassInstrumentation(Example.class);
Method tested = Example.class.getDeclaredMethod("test", String.class);
Method breakpoint = List.class.getDeclaredMethod("add", Object.class);
CodePosition codePosition = instrumentation.afterCall(tested, breakpoint);
InterleavedRunner.interleave(new ExampleMain(), new ExampleSecondary(), Arrays.asList(codePosition)).throwExceptionsIfAny();
}
}
The stack trace says:
java.lang.IllegalArgumentException: Class Example is not instrumented
at
com.google.testing.threadtester.CallLoggerFactory.getClassInstrumentation(CallLoggerFactory.java:108)
at
com.google.testing.threadtester.Instrumentation.getClassInstrumentation(Instrumentation.java:65)
at MyTest.testThreadWeaver(MyTest.java:92
I followed the instructions at the official Google code webpage, but it does not seem to work. Any ideas?
ThreadWeaver needs to instrument your classes in order to add breakpoints to your methods. Therefore, you cannot run the tests with JUnit directly but you must run your test from a specific test runner. For your case this would be ThreadedTestRunner. The actual test methods must then be annotated with #ThreadedTest instead of #Test. This should work:
#Test
public void startTest() throws Exception {
new ThreadedTestRunner().runTests(getClass(), Example.class);
}
#ThreadedTest
public void testThreadWeaver() throws Exception {
// here comes your test
}
In a Blackbox test environment I would need to include CODE 1 and end with CODE 2 to perform a test by running Android JUnit Test (as explained from the Robotium site):
CODE 1:
public class ConnectApp extends ActivityInstrumentationTestCase2 {
private static final String LAUNCHER_ACTIVITY_FULL_CLASSNAME="com.example.android.notepad.NotesList";
private static Class<?> launcherActivityClass;
private Solo solo;
static {
try { launcherActivityClass=Class.forName(LAUNCHER_ACTIVITY_FULL_CLASSNAME); }
catch (ClassNotFoundException e) { throw new RuntimeException(e); }
}
public ConnectApp() throws ClassNotFoundException {
super(launcherActivityClass);
}
public void setUp() throws Exception {
this.solo = new Solo(getInstrumentation(), getActivity());
}
CODE 2:
public void testNumberOne() { … }
public void testNumberTwo() { … }
}
However, I would like to abstract CODE 1 of the code ( which includes getInstrumentation() and getAcitvity()) so that I can simply call them in a separate test file and then run CODE 2 . This is because I want to have tests in separate files and don't want to keep adding the same amount of CODE 1 code but just call a method/constructor to initiate the process.
Is there a way to do this? Thank you in advance.
yes there is a way to do this. What you will need to do is create an empty test class such as:
public class TestTemplate extends ActivityInstrumentationTestCase2 {
private static final String LAUNCHER_ACTIVITY_FULL_CLASSNAME="com.example.android.notepad.NotesList";
private static Class<?> launcherActivityClass;
private Solo solo;
static {
try { launcherActivityClass=Class.forName(LAUNCHER_ACTIVITY_FULL_CLASSNAME); }
catch (ClassNotFoundException e) { throw new RuntimeException(e); }
}
public ConnectApp() throws ClassNotFoundException {
super(launcherActivityClass);
}
public void setUp() throws Exception {
super.setUp();//I added this line in, you need it otherwise things might go wrong
this.solo = new Solo(getInstrumentation(), getActivity());
}
public Solo getSolo(){
return solo;
}
}
Then for every test class you want in the future instead of extending ActivityInstrumentationTestCase2 you will extend TestTemplate.
for example:
public class ActualTest extends TestTemplate {
public ActualTest() throws ClassNotFoundException {
super();
}
public void setUp() throws Exception {
super.setUp();
//anything specific to setting up for this test
}
public void testNumberOne() { … }
public void testNumberTwo() { … }
}