How to set a #Value in a MicronautTest? - java

I am using Micronaut as framework for developing an AWS Java Lambda.
Micronaut supports #Value for reading, well, "values".
#io.micronaut.context.annotation.Factory
public class SomeFactory {
public SomeFactory(
#io.micronaut.context.annotation.Value("${NameOfValue}")
final String value) {
...
}
...
}
When testing, I want to set "NameOfValue" to a specific value, how can I do that?
#io.micronaut.test.annotation.MicronautTest
class SomeLambdaIT {
#org.junit.jupiter.api.Test
void aTest() {
// When this test runs, "NameOfValue" shall be set to a specific value
}
}

When testing, I want to set "NameOfValue" to a specific value, how can
I do that?
You have a number of options.
One option is to define src/test/resources/application-test.yml and define the config setting there. That file will only be loaded in the test environment and any settings defined in that file will supersede values defined in src/main/resources/application.yml.
Another option that might make sense if you only want the special setting in play for this particular test is you can do something like this...
import io.micronaut.test.annotation.MicronautTest;
import org.junit.jupiter.api.Test;
#MicronautTest(propertySources = "classpath:some-special-test-props.properties")
public class SomeTest {
#Test
void someTest() {
// ...
}
}
Then define src/test/resources/some-special-test-props.properties and assign the value there.
Yet another option is to mark your test with #Property:
import io.micronaut.context.annotation.Property;
import io.micronaut.test.annotation.MicronautTest;
import org.junit.jupiter.api.Test;
#MicronautTest
#Property(name="some.config.value", value = "My Test Value")
public class SomeTest {
#Test
void someTest() {
// ...
}
}
I hope that helps.
EDIT
A comment below includes "I did give it a try, but the #Property solution nor the some-special-test-props.properties works in my case.". I have created a sample app demonstrating each of these techniques. See the project at https://github.com/jeffbrown/markusschultevalue.
https://github.com/jeffbrown/markusschultevalue/blob/8131e96492356180e2c7fade09603bd41f8c8829/src/main/java/markusschultevalue/SomeWidget.java
package markusschultevalue;
public class SomeWidget {
private final String name;
public SomeWidget(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
https://github.com/jeffbrown/markusschultevalue/blob/master/src/main/java/markusschultevalue/SomeFactory.java
package markusschultevalue;
import io.micronaut.context.annotation.Bean;
import io.micronaut.context.annotation.Factory;
import io.micronaut.context.annotation.Value;
#Factory
public class SomeFactory {
private final String name;
// there are better ways to do this but
// this is consistent with the code in the
// question being asked...
public SomeFactory(#Value("${some.config.value}") String name) {
this.name = name;
}
#Bean
public SomeWidget createWidget() {
return new SomeWidget(name);
}
}
https://github.com/jeffbrown/markusschultevalue/blob/8131e96492356180e2c7fade09603bd41f8c8829/src/test/java/markusschultevalue/PropertyAnnotationTest.java
package markusschultevalue;
import io.micronaut.context.annotation.Property;
import io.micronaut.test.annotation.MicronautTest;
import org.junit.jupiter.api.Test;
import javax.inject.Inject;
import static org.junit.jupiter.api.Assertions.assertEquals;
#MicronautTest
#Property(name="some.config.value", value="Some Widget Name")
public class PropertyAnnotationTest {
#Inject
SomeWidget someWidget;
#Test
void testWidget() {
assertEquals("Some Widget Name", someWidget.getName());
}
}
https://github.com/jeffbrown/markusschultevalue/blob/8131e96492356180e2c7fade09603bd41f8c8829/src/test/java/markusschultevalue/ConfigFileTest.java
package markusschultevalue;
import io.micronaut.test.annotation.MicronautTest;
import org.junit.jupiter.api.Test;
import javax.inject.Inject;
import static org.junit.jupiter.api.Assertions.assertEquals;
// This will load the config value
// from src/test/resources/some-widget-test-config.yml
#MicronautTest(propertySources = "classpath:some-widget-test-config.yml")
public class ConfigFileTest {
#Inject
SomeWidget someWidget;
#Test
void testWidget() {
assertEquals("Some Other Widget Name", someWidget.getName());
}
}
https://github.com/jeffbrown/markusschultevalue/blob/8131e96492356180e2c7fade09603bd41f8c8829/src/test/resources/some-widget-test-config.yml
some:
config:
value: Some Other Widget Name
Note that in your example you are referencing a config variable with "${NameOfValue}". If that is actually the name of your config variable, note that in code you need to reference that in valid kebab-case which would be "${name-of-value}".
I hope that helps.

Related

Mockito when not resetting between Tests [duplicate]

I am seeing behaviour that I believe is a bug. #InjectMocks does not seem to create a new test subject before every test method. Where as #Mock does. In the following example, if Subject.section is final one #Test fails. If its not final both pass. My current workaround is to use #BeforeClass, but this is not ideal.
Subject.java:
package inject_mocks_test;
public class Subject {
private final Section section;
public Subject(Section section) {
this.section = section;
}
public Section getSection() {
return section;
}
}
Section.java:
package inject_mocks_test;
public class Section {}
SubjectTest.java
package inject_mocks_test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
import static org.testng.Assert.assertEquals;
public class SubjectTest {
#Mock
Section section;
#InjectMocks
Subject subject;
#BeforeMethod
public void setup() {
MockitoAnnotations.initMocks(this);
}
#Test
public void test1() {
assertEquals(section, subject.getSection());
}
#Test
public void test2() {
assertEquals(section, subject.getSection());
}
}
Cheers.
You are using the #InjectMocks for constructor incjection. This will work as long as Mockito finds the field not initalized (null). JUnit is creating a new instance of the test class before each test, so JUnit fans (like me) will never face such problem. TestNg is not creating a new instance of test class. It's keeping the state between test methods, so when MockitoAnnotations.initMocks(this) is called for the second time, Mockito will find subject field already initialized and will try to use field injection. This on the other turn will work until the field is not final.
Is this is a bug? I believe not - rather a natural consequence of the API design.
Some workaround for you would be to add
this.subject = null;
in some #AfterMethod method.

how to use System.getenv in Junit PowerMockito

I'm able to mock the System.getenv value from Junit but when I execute the test case - in my service class System.getevn value coming as null. Not sure what I'm doing wrong here. Please find my test service class and junit class.
Can some please help me to fix this issue - why the value is not setting in my actual service class?
TestService.java
public class TestService {
public TestService() throws Exception {
loadTestMethod();
}
private void loadTestMethod() {
System.out.println("Environment vairlable : " + System.getenv("my_key_name"));
System.setProperty("app.key", System.getenv("my_key_name"));
}
}
TestServiceTest.java
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PowerMockIgnore;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
#RunWith(PowerMockRunner.class)
#PrepareForTest(value = { System.class })
#PowerMockIgnore("javax.management.*")
public class TestServiceTest {
#Mock
TestService testService;
#Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
PowerMockito.mockStatic(System.class);
PowerMockito.when(System.getenv("my_key_name")).thenReturn("Testing");
System.out.println("Junit Environment vairlable : " + System.getenv("my_key_name"));
testService = new TestService();
}
#Test
public void myServiceTest() {
}
}
Just because PowerMockito allows us to mock static does not mean that we should.
Your classes are dependent on static implementation concerns that make unit testing in isolation, in most cases, difficult.
Consider following the Explicit Dependency Principle
Methods and classes should explicitly require (typically through method parameters or constructor parameters) any collaborating objects they need in order to function correctly.
Create an abstraction of the desired functionality
public interface SystemWrapper {
//The "standard" output stream
PrintStream out;
//Gets the value of the specified environment variable
string getenv(string name);
//Sets the system property indicated by the specified key.
string setProperty(String key, String value);
}
The implementation will encapsulate the actual calls to the static system class
public class SystemWrapperImplementation implements SystemWrapper {
//The "standard" output stream
public final PrintStream out = System.out;
//Gets the value of the specified environment variable
public string getenv(string name) {
return System.getenv(name);
}
//Sets the system property indicated by the specified key.
public string setProperty(String key, String value) {
return System.setProperty(key, value);
}
}
Your dependent class will then need to be refactored to include the abstraction
public class TestService {
private SystemWrapper system;
public TestService(SystemWrapper system) throws Exception {
this.system = system;
string key = "app.key";
string name = "my_key_name";
loadTestMethod(key, name);
}
private void loadTestMethod(string key, string name) {
string environmentVariable = system.getenv(name);
system.out.println("Environment variable : " + environmentVariable);
system.setProperty(key, environmentVariable);
}
}
Now for testing you can mock the necessary dependencies as needed without any adverse effects. The implementation will then be used in production when invoking actual code.
Finally I would suggest not having your constructors throwing exceptions. Constructors should mainly be used for assignments of variables.

Proxy for abstract class without changing the usage

I have an abstract class (database mapping) implementing an interface where default implementations are injected at runtime (this is part of another library and cannot be changed).
I want to override one of the default implementation via a proxy (as that seems like the way to override this).
public abstract class Table1 implements Storable<Table1>
{
#Sequence("ID_SEQUENCE")
#Alias("ID")
public abstract String getID();
public abstract void setID(String ID);
#Alias("NAME")
public abstract String getAvailabilityZone();
public abstract void setAvailabilityZone(String value);
}
public interface Storable<S extends Storable<S>> {
//a bunch of method definition.
boolean tryLoad() throws Exception;
}
Let's say I want to override tryLoad() method to do my own things instead of what the generated code provides. Given the nature of the library, it is not something I can achieve by simple #Override.
The simple way this is currently used is as following:
public void method() {
Table1 t = Repository.storageFor(Table1.class).prepare();
t.setName( "temp" );
if (!t.tryLoad())
t.tryInsert();
}
I want to proxy tryLoad() without making changes in all the methods across the whole codebase - that would be to get proxied instance instead of actual one and perform the operation on that.
Is there any recommended way to achieve this?
Thanks!
I woke up last night and felt bored, so despite your lack of feedback I created a little Carbonado showcase project and shared it on GitHub. I made three commits:
Initial commit with Maven project already prepared for AspectJ and a JUnit test for me to find out how Carbonado actually works, because I had never used it before.
Add failing unit test for behaviour of tryLoad() expected to be provided by aspect.
Add aspect to make unit test pass. Aspect hooks into tryLoad() and auto-creates non-existent record. I do not know if I guessed right what you actually wanted to achieve, but if it was a different thing, just change the aspect implementation.
Sample code
Carbonado storable:
package de.scrum_master.app;
import com.amazon.carbonado.Nullable;
import com.amazon.carbonado.PrimaryKey;
import com.amazon.carbonado.Storable;
#PrimaryKey("ID")
public interface StoredMessage extends Storable<StoredMessage> {
long getID();
void setID(long id);
#Nullable String getMessage();
void setMessage(String message);
}
Aspect:
package de.scrum_master.aspect;
import com.amazon.carbonado.Storable;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
#Aspect
public class CarbonadoAspect {
#Around("call(boolean tryLoad()) && target(storable)")
public boolean tryInsertIfNotFound(ProceedingJoinPoint thisJoinPoint, Storable storable) throws Throwable {
System.out.println(thisJoinPoint);
if ((boolean) thisJoinPoint.proceed())
return true;
System.out.println("Not found: " + storable + " -> inserting");
return storable.tryInsert();
}
}
JUnit test:
package de.scrum_master.app;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import com.amazon.carbonado.FetchException;
import com.amazon.carbonado.PersistException;
import com.amazon.carbonado.Repository;
import com.amazon.carbonado.RepositoryException;
import com.amazon.carbonado.Storage;
import com.amazon.carbonado.SupportException;
import com.amazon.carbonado.repo.map.MapRepositoryBuilder;
import de.scrum_master.app.StoredMessage;
public class CarbonadoTest {
private Repository repo;
private Storage<StoredMessage> storage;
StoredMessage message;
#Before
public void setUp() throws Exception {
repo = MapRepositoryBuilder.newRepository();
storage = repo.storageFor(StoredMessage.class);
message = storage.prepare();
}
#After
public void tearDown() throws Exception {
repo.close();
repo = null;
storage = null;
message = null;
}
// (...)
#Test
public void aspectCreatesNonExistentRecord() throws SupportException, RepositoryException {
message.setID(1);
// Without the aspect this would be false
assertTrue(message.tryLoad());
assertEquals(message.getID(), 1);
assertEquals(message.getMessage(), null);
}
}
Enjoy!

Autowire dependency in builder class with static instantiation method

I'm pondering this builder class that should calculate a hash from the field values. Maybe this in itself is wrong for starters, but at the moment it seems to me that it belongs there because I'm striving to an immutable Article.
I would like to autowire/inject ArticleMD5HashCalculator but when I put #Autowired on the field, IntelliJ complains: field injection is not recommended. Constructor injection is not possible because it's a builder pattern class, which means it has a private constructor without parameters and a static method for instantiation where it would be awkward to pass in hashCalculator.
The builder is injected into a scraper. The scraper will reuse the same builder for many articles. When Spring creates the builder with prototype scope, the builder will carry old values when the next article doesn't overwrite the old values.
New'ing the hashCalculator results is a hard dependency, making it impractical to inject mocks. What is the best way to handle this situation?
Here's the code of how it is now:
import org.observer.media.utils.ArticleMD5HashCalculator;
import org.observer.media.utils.MD5HashCalculator;
import java.time.ZonedDateTime;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class ArticleBuilder {
private ArticleMD5HashCalculator hashCalculator;
private String headline;
private String subheading;
private String lead;
// other article fields...
private ArticleBuilder() {
// This seems wrong.
this.hashCalculator = new ArticleMD5HashCalculator(new MD5HashCalculator());
}
public static ArticleBuilder article() {
return new ArticleBuilder();
}
public ArticleBuilder withHeadline(String headline) {
this.headline = headline;
return this;
}
//Other with-methods...
public Article build() {
// calculateHash() is called in the 9th argument.
return new Article(headline, subheading, lead, body, images, quotations, subArticles, url, calculateHash(), author, sources, category, subjects, index, medium, company, datePublished, dateFetched);
}
private String calculateHash() {
return hashCalculator.hash(headline, subheading, lead, body, quotations, datePublished, dateFetched);
}
}
Assumptions:
There is one to one relationship between ArticleBuilder and ArticleMD5HashCalculator. Meaning you don't plan to inject different instances of hashCalculator into ArticleBuilder at different places in the project (essentially having multiple instances of ArticleBuilder)
You can change the ArticleBuilder impl as follows
public class ArticleBuilder {
private ArticleMD5HashCalculator hashCalculator;
public ArticleBuilder(ArticleMD5HashCalculator hashCalculator) {
this.hashCalculator = hashCalculator;
}
}
You can create a spring bean of type ArticleMD5HashCalculator and have this injected into a spring bean of type ArticleBuilder the following way.
#Configuration
public class ArticleConfig {
#Bean
public ArticleMD5HashCalculator articleMD5HashCalculator() {
return new ArticleMD5HashCalculator(new MD5HashCalculator());
}
#Bean
public ArticleBuilder() {
return new ArticleBuilder(articleMD5HashCalculator());
}
}
You can autowire ArticleBuilder elsewhere in your project and use it as a builder.
I am not sure why you made a private constructor and a static method to invoke that. I assume it is because you want a singleton ArticleBuilder. That can be achieved with the above approach. Correct me if I am wrong about this.
Update 1:
Based on the information you provided in the comments, you are injecting ArticleBuilder in a Scraper object and you want to have a way of getting a new instance of ArticleBuilder every time. You can use spring #Lookup annotation for that.
Stub implementation of Scraper class.
public class Scraper {
//assuming this is the method where you want to use ArticleBuilder
public void scrape() {
getArticleBuilder();
}
//You can even pass constructor arguments to this method.
//They will be used to match a constructor on the target bean and that gets invoked
#Lookup
public ArticleBuilder getArticleBuilder() {
//Spring creates a runtime implementation of this method.
return null;
}
}
You can call getArticleBuilder anytime you want a new instance of the bean. If it is declared prototype, you will always get a new instance of the bean.
But the only caveat with this is that Lookup annotation is not going to work with beans created with #Bean annotation. You alternate config may look like this.
#Component
#Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class ArticleBuilder {
#Autowired
private ArticleMD5HashCalculator hashCalculator;
public ArticleBuilder(ArticleMD5HashCalculator hashCalculator) {
this.hashCalculator = hashCalculator;
}
}
#Component
public class ArticleMD5HashCalculator {
public ArticleMD5HashCalculator(MD5HashCalculator hashCalculator) {
this.hashCalculator = hashCalculator;
}
}
beans.xml:
<beans>
<bean class="MD5HashCalculator" />
<!-- Fully qualified class name is needed -->
</beans>
Also due to convention used in Spring documentation please use constructor-based injection when possible.
The Spring team generally advocates constructor injection as it enables one to implement application components as immutable objects and to ensure that required dependencies are not null.
Full info (scroll a little): Spring DOCS
I brewed up this alternative approach to pull out the new'ing and to open a window for injecting mocks. The solution implies that the builder has to be instantiated and recreated by a factory.
The factory:
import org.observer.media.hash.ArticleHashCalculator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.time.ZonedDateTime;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
#Component
public class ArticleBuilderFactory {
private ArticleHashCalculator articleHashCalculator;
#Autowired
public ArticleBuilderFactory(ArticleHashCalculator articleHashCalculator) {
this.articleHashCalculator = articleHashCalculator;
}
public ArticleBuilder create() {
return new ArticleBuilder(articleHashCalculator);
}
public class ArticleBuilder {
private ArticleHashCalculator articleHashCalculator;
private String headline;
private String subheading;
//...
private ArticleBuilder(ArticleHashCalculator articleHashCalculator) {
this.articleHashCalculator = articleHashCalculator;
}
public ArticleBuilderFactory.ArticleBuilder withIndex(int index) {
this.index = index;
return this;
}
public ArticleBuilderFactory.ArticleBuilder withHeadline(String headline) {
this.headline = headline;
return this;
}
//...
public Article build() {
return new Article(headline, subheading, lead, body, images, quotations, subArticles, url, calculateHash(), author, sources, category, subjects, index, medium, company, datePublished, dateFetched);
}
private String calculateHash() {
return articleHashCalculator.hash(headline, subheading, lead, body, quotations, datePublished, dateFetched);
}
}
}
Usage of the factory:
import org.junit.Test;
import org.junit.runner.RunWith;
import org.observer.media.hash.ArticleMD5HashCalculator;
import org.observer.media.hash.MD5HashCalculator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringRunner;
import static org.assertj.core.api.Java6Assertions.assertThat;
#RunWith(SpringRunner.class)
#ContextConfiguration(classes = {
ArticleBuilderFactory.class,
MD5HashCalculator.class,
ArticleMD5HashCalculator.class
})
public class ArticleBuilderFactoryTest {
private static final String HEADLINE = "headline";
private static final String LEAD = "lead";
private static final String BODY = "body";
#Autowired
private ArticleBuilderFactory articleBuilderFactory;
#Autowired
private ArticleMD5HashCalculator hashCalculator;
#Test
public void build() {
ArticleBuilderFactory.ArticleBuilder articleBuilder = articleBuilderFactory.create();
Article article = articleBuilder
.withHeadline(HEADLINE)
.withLead(LEAD)
.withBody(BODY)
.build();
assertThat(article.getHeadline()).isEqualTo(HEADLINE);
assertThat(article.getLead()).isEqualTo(LEAD);
assertThat(article.getBody()).isEqualTo(BODY);
assertThat(article.getHash()).isEqualTo(hashCalculator.hash(HEADLINE, null, LEAD, BODY, null, null, null));
}
}
ArticleMD5HashCalculator has #Component:
#Component
public class ArticleMD5HashCalculator {
}

How to set up already consistent data for Google App Engine unit tests?

I know that App Engine datastore queries are only eventually consistent. However, for some of my tests, I would like to seed the datastore with already consistent data (i.e. it was saved a long time before the test occurred and is now globally consistent).
How can I make sure that the initial data is consistent before running the tests? I would like to still be able to require that actions under test do not require immediate consistency.
I'm using Google Cloud Endpoints for Java, but I'm not anything specific to Endpoints here.
I ended up creating the following BaseTest class and having all of my tests inherit from that:
package com.example;
import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.dev.HighRepJobPolicy;
import com.google.appengine.tools.development.testing.LocalDatastoreServiceTestConfig;
import com.google.appengine.tools.development.testing.LocalServiceTestHelper;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
public class BaseTest {
public static final class Policy implements HighRepJobPolicy {
static boolean shouldApply = false;
public static void applyAll() {
shouldApply = true;
}
public static void applyNone() {
shouldApply = false;
}
#Override
public boolean shouldApplyNewJob(Key entityGroup) {
return shouldApply;
}
#Override
public boolean shouldRollForwardExistingJob(Key entityGroup) {
return shouldApply;
}
}
public final LocalServiceTestHelper helper =
new LocalServiceTestHelper(new LocalDatastoreServiceTestConfig()
.setAlternateHighRepJobPolicyClass(Policy.class));
#Before
public void setUp() {
helper.setUp();
}
#After
public void tearDown() {
helper.tearDown();
}
}
Then tests can be of the form:
#Test
public void thingShouldDoX() throws Exception {
Policy.applyAll();
// Do setup here, everything inside will be consistent.
Policy.applyNone();
// Run code under test here, without consistency.
}

Categories