How to get to a WireMockServer from Junit 5 WireMockTest test case - java

Wire mock has a addMockServiceRequestListener function available on the JUnit4 Rule or on a wiremock server instance.
How do I get to that function from a test class annotated with JUnit 5's #WireMockTest annotation?
More generally, how do I get an instance of the WireMockServer from a test in a class that uses #WireMockTest ?

There's a better option in newer versions of WireMock than calling addMockServiceRequestListener, which is to register a PostServeAction implementation as an extension when configuring JUnit:
#RegisterExtension
static WireMockExtension wm =
WireMockExtension.newInstance()
.options(wireMockConfig().dynamicPort()
.extensions(new PostServeAction() {
#Override
public String getName() {
return "my-action";
}
#Override
public void doGlobalAction(ServeEvent serveEvent, Admin admin) {
// Do something
}
}))
.build();
PostServeAction implementations are the "proper" way to listen for events and will still work in future versions, whereas listeners will be deprecated and removed eventually. They also are given more context about the request than listeners.

Would retrieving the DSL from WireMockRunTimeInfo sufficient in your case?
https://wiremock.org/docs/junit-jupiter/
https://javadoc.io/doc/com.github.tomakehurst/wiremock-jre8/latest/com/github/tomakehurst/wiremock/junit5/WireMockRuntimeInfo.html#getWireMock--
From WireMockRunTimeInfo , there is a getWireMock() method which returns WireMock.
Example:
#WireMockTest
public class DeclarativeWireMockTest {
#Test
void test_something_with_wiremock(WireMockRuntimeInfo wmRuntimeInfo) {
// The static DSL will be automatically configured for you
stubFor(get("/static-dsl").willReturn(ok()));
// Instance DSL can be obtained from the runtime info parameter
WireMock wireMock = wmRuntimeInfo.getWireMock();
wireMock.register(get("/instance-dsl").willReturn(ok()));
// Info such as port numbers is also available
int port = wmRuntimeInfo.getHttpPort();
// Do some testing...
}
}

Related

SpringBoot pass local variable

I'm creating a Java application that depending on certain conditions/configurations it instantiates a SpringBoot application to receive some HTTP messages.
My problem is that I have a ReceiverService that needs to use some variables that are created outside of the SpringBoot application. Is there a way to pass local java variables (from inside the application, not outside like the shell or files) to SpringBoot components?
Example:
I have a Manager object that, depending on some conditions, it defines a variable param that I want to use in the SpringBoot Component ReceiverService.
public class Manager {
public Manager(bool condition) {
String param = "foo";
if (condition) {
param = "bar";
}
ReceiverApp receiver = new ReceiverApp(); // init SpringBoot app
}
}
The SpringBoot app:
#SpringBootApplication
public class ReceiverApp {
public ReceiverApp() {
SpringApplication.run(ReceiverApp.class);
}
#Component
public class ReceiverService implements InitializingBean {
final CustomObject obj1 = new CustomObject(param);
#Override
public void aFunction() throws Exception {
MyConfig config = MyConfig.build(param);
}
}
SpringApplication.run is designed to accept key=value pairs like the ones you give in command line parameters to the main method in Java.
Since you seem to have the other Spring boot application jar in your class-path, and seem to be able to just instanciate the ReceiverApp, you could just pass the parameters as strings (of the format String[]{"key1=value1", "key2=value2"})
These can be passed to SpringApplication.run, and these will automatically become Spring configuration values, which can be injected anywhere in the application.
#SpringBootApplication
public class ReceiverApp {
public ReceiverApp(String[] notReallyFromCommandLineArgs) {
SpringApplication.run(ReceiverApp.class, notReallyFromCommandLineArgs);
}
You can send the parameters like this:
String[] params = new String[]{"my.params.param1="+param1};
ReceiverApp receiver = new ReceiverApp(params);
You can inject them anywhere in that Receiver Spring application as a value.
#Value("my.params.param1")
String theParam1;
Refer:
https://stackoverflow.com/a/55890457/1364747
There are several ways to create a manager app which configures another app.
Scenario 1
A common way is to put the config in a database which is accessed directly by both apps, although this is less clean (it creates a hard dependency via the database).
Scenario 2
A cleaner solution is if the manager app owns the database, and offers a config service which is consumed (and presumably cached) by the configured app. Typically the config service would be accessed via remoting, e.g. REST, so the two apps can be deployed and run independently.
Scenario 3
If you want to keep it simple, you could reverse the setup and implement the config service in the configured app itself (sort of like the management interface in Tomcat). Then you could either add a web UI in the same app and be done with it, or build a separate standalone client which interacts with that service. In this last two scenarios, think about security because you might not want any client to be able to connect and change the config.
You can have ReceiverService inject a Supplier<String> (or define your own interface if you prefer a less generic naming) and make Manager implement it.
#Component
public class ReceiverService implements InitializingBean {
#Autowired
private Supplier<String> paramSupplier;
final CustomObject obj1 = new CustomObject(param);
#Override
public void aFunction() throws Exception {
MyConfig config = MyConfig.build(paramSupplier.get());
}
}
public class Manager implements Supplier<String> {
private final String param;
public String get() { return param; }
public Manager(bool condition) {
param = "foo";
if (condition) {
param = "bar";
}
// why is this in the Manager constructor???
ReceiverApp receiver = new ReceiverApp(); // init SpringBoot app
}
}
Or you define your own #Component to supply the parameter and have both manager and receiver inject it.

How to have DropWizard JUnit App Rule definition use startup information from a docker rule?

The general problem I am trying to solve is this. I have a solution, but it's very clunky, and I'm hoping someone knows of a more orderly one.
Dropwizard offers a JUnit TestRule called DropwizardAppRule, which is used for integration tests. You use it like this:
#ClassRule
public static final DropWizardAppRule<MyConfiguration> APP_RULE = new DropwizardAppRule(MyApplication.class, myYmlResourceFilePath, ConfigOverride("mydatabase.url", myJdbcUrl));
It will start up your application, configuring it with your yml resource file, with overrides that you specified in the constructor. Note, however, that your overrides are bound at construction time.
There are also JUnit rules out there to start up a Docker container, and I'm using one to start up MySql, and a JUnit RuleChain to enforce the fact that the container must start up before I launch my Dropwizard application that depends on it.
All that works great, if I'm willing to specify in advance what port I want the MySql container to expose. I'm not. I want these integration tests to run on a build machine, quite possibly in parallel for branch builds of the same project, and I would strongly prefer to use the mechanism where you ask Docker to pick any available port, and use that.
The problem I run into with that, is that the exposed container port is not known at the time that the DropwizardAppRule is constructed, which is the only time you can bind configuration overrides.
The solution I adopted was to make a wrapper JUnit Rule, like so:
public class CreateWhenRunRuleWrapper<T extends ExternalResource> extends ExternalResource {
private final Supplier<T> wrappedRuleFactory;
private T wrappedRule;
public CreateWhenRunRuleWrapper(Supplier<T> wrappedRuleFactory) {
this.wrappedRuleFactory = wrappedRuleFactory;
}
public T getWrappedRule() {
return wrappedRule;
}
#Override
protected void before() throws Throwable {
wrappedRule = wrappedRuleFactory.get();
wrappedRule.before();
}
#Override
protected void after() {
wrappedRule.after();
}
}
This works, allowing me to construct the DropWizardAppRule class in the before() method, but is quite obviously outside JUnit's design intent, as shown by the fact that I had to locate it in the org.junit.rules package, in order to empower my class to be able to call the before() and after() methods of the late-created Rule.
What would be a more orderly, best practice way to accomplish the same objective?
2 Options we came up with:
The hacky solution is to use static {} which executes the code after spinning up the container but before initialising the dropwizard instance:
public static final GenericContainer mongodb = new GenericContainer("mongo:latest").withExposedPorts(27017);
static {
mongodb.start();
System.setProperty("dw.mongoConfig.uri", "mongodb://" + mongodb.getContainerIpAddress() + ":" + mongodb.getMappedPort(27017));
}
#ClassRule
public static final DropwizardIntegrationAppRule<Config> app1 = new DropwizardIntegrationAppRule<>(Service.class);
The second option is cleaner and much like yours.
private static final MongoDContainerRule mongo = new MongoDContainerRule();
private static final DropwizardIntegrationAppRule<Config> app = new DropwizardIntegrationAppRule<>(Service.class);
#ClassRule
public static final RuleChain chain = RuleChain
.outerRule(mongo)
.around(app)
MongoDContainerRule is like your wrapper but it also sets the right port through system properties.
public class MongoDContainerRule extends MongoDBContainerBase {
private static final GenericContainer mongodb = new GenericContainer("mongo:latest").withExposedPorts(27017);
#Override
protected void before() throws Throwable {
mongodb.start();
System.setProperty("dw.mongoConfig.uri", "mongodb://" + mongodb.getContainerIpAddress() + ":" + mongodb.getMappedPort(27017));
System.setProperty("dw.mongoConfig.tls", "false");
System.setProperty("dw.mongoConfig.dbName", DB_NAME);
}
#Override
protected void after() {
mongodb.stop();
}
}
The container will expose mongodb on a free port. mongodb.getMappedPort(internalPort) will return it. System.setProperty("dw.*") injects values into the dropwizard config.

How to unit test logging error with Spock framework in groovy in a Spy-Class

I have a Class which has methods in it which I've to mock.
This is why I use Spy():
MyClass myClass = Spy(MyClass)
With following question:
How to unit test logging error with Spock framework in groovy
I could successfully get the logging message, but for this one, I'm not able to use just a normal instantiation of the class like:
MyClass myClass = new MyClass()
How is it possible to get the logging message in a Spock test, when the Class is a Spy?
A generic way to test logging is to write a simple appender which stores events in memory, set up the logging configuration to use it in tests, and then, after the tested code is run, get the logged events and verify them.
Assuming Logback is used, the test appender can be written e.g. like this:
public class InMemoryAppender extends AppenderBase<ILoggingEvent> {
private static final List<String> events = new ArrayList<>();
public static synchronized List<String> getEvents() {
return new ArrayList<>(events);
}
#Override
protected void append(ILoggingEvent event) {
synchronized(InMemoryAppender.class){
events.add(event.getFormattedMessage());
}
}
}
I don't think the Spy has anything to help out with this, because it spies on the object's methods, not on its internal behavior.

Is it possible to run (via maven) select junit selenium tests based on a custom annotation

Tried to get all the good keywords in the question. Basically I have a number of selenium tests, using JUnit4/Maven and created a custom annotation to markup each test with some basic info:
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.METHOD)
public #interface TestInfo {
public enum Priority { LOW, MEDIUM, HIGH }
Priority priority() default Priority.LOW;
String useCase() default "";
String createdBy() default "unknown";
String lastModified() default "unknown";
}
So each test looks like this:
#Test
#TestInfo(priority = TestInfo.Priority.HIGH,
createdBy = "MivaScott",
lastModified = "2016/11/29",
useCase = "Log into website with valid credentials")
public void loginValidCredentials() throws Exception {
Properties user = Data.getUserCredentials("default");
loginPage.setLogin(user.getProperty("username"));
loginPage.setPassword(user.getProperty("password"));
loginPage.clickSignInButtonAndWait();
Verify.titleContains(MyConstants.TITLE_DASHBOARD, "");
}
What I'm hoping for is that I can specify on the command like to only run tests that are marked as being HIGH priority. So something to the effect of:
mvn -DTestInfo.priority=HIGH test
Is this possible, or something similar?
There are two possible ways I can think to resolve this.
Create a custom test runner that parses your system property and only runs test methods with the matching annotation.
public class PrioritzedTestRunner extends BlockJUnit4ClassRunner {
#Override
protected void runChild(final FrameworkMethod method, RunNotifier notifier) {
String priority = System.getProperty("TestInfo.priority");
TestInfo info = method.getAnnotation(TestInfo.class);
if (priority == null || info == null) {
//If the configuration is blank or the test is uncategorized then run it
super.runChild(method, notifier);
} else if (priority != null) {
//try to resolve the priority and check for a match.
TestInfo.Priority configPri = TestInfo.Priority.valueOf(priority.toUpperCase());
if (info.equals(configPri)) {
super.runChild(method, notifier);
}
}
}
You would need to add the RunWith annotation to your test classes.
#RunWith(PrioritizedTestRunner.class)
public voidMyTestClass() {
#Test
#TestInfo(...)
public void testThing1(){}
#Test
#TestInfo(...)
public void testThing2(){}
}
If The tests are fairly static, separate them into classes rather than annotations and use a custom maven profile to execute the test collection based on commonly-named files or resources.
I haven't configured this myself, but I've seen it done. you should be able to have maven test-phases targeting your PriorityLevels.
http://maven.apache.org/guides/introduction/introduction-to-profiles.html
at which point you should be able to execute each priority level as a separate mvn command, if I'm reading the documentation correctly.
Best of Luck
I believe this feature can be implemented by using tags in your junit test cases.
#WithTag(type="epic", name="Audit")
Reference: http://thucydides.info/docs/thucydides/_adding_tags_to_test_cases.html

Power Mockito fails to mock constructor

In order to test some legacy code, I have to use Power Mockito. Reason is that the legacy code is not using dependency injection and due to some reasons, we can't refactor the code at this time. We are running testng with ANT in our system. I have configured build.xml to use power mock and power mock testng libraries. I want to mock a constructor using Power Mockito and below is the sample code.
public class Something {
private String arg = null;
public Something() {
}
public Something(String _arg) {
arg = _arg;
}
public String doSomething() {
return arg;
}
}
public class Helper {
public Something doSomething(String arg) {
return new Something();
}
}
#PrepareEverythingForTest
class TestSC {
#Test
public void testHelper() throws Exception {
Something mockSomething = PowerMockito.mock(Something.class);
PowerMockito.whenNew(Something.class).withNoArguments().thenReturn(mockSomething);
Helper helper = new Helper();
Something test = helper.doSomething("arg");
Assert.assertEquals(test, mockSomething);
}
}
This test fails and I have no clue what is going on wrong here. Also I have seen below link to configure testng with power mockito. https://github.com/jayway/powermock/wiki/TestNG_usage
I tried extending my test class to PowerMockTestCase and it gaves me below error while running test.
[testng] [TestNG] [ERROR]
**[testng] Error creating object factory**
[testng] The tests failed.
I have below doubts in mind:-
1) Either my testng is not configured properly to use Power Mockito, but power mockito simple testcase works.
2) Some configuration is missing.
I figure out the issue lately, it was because of some dependency library i.e.javassist which was quite old. Replacing it with the newer version 3.20 resolved the issue and PowerMockito constructor mocking worked.

Categories

Resources