Test and Runtime getting data from different sources - java

I have a Spring application which gets data from an API. We test over Jenkins and the problem is that Jenkins doesn't have access to this API.
So our solution is to embedded some sample files with these API endpoints, to src/test/resources.
But the code is becoming a mess since I don't know how to differ if it's testing or running.
For example:
private void loadDataFromEndpointOne(boolean isTest) {
List<String> someData = new ArrayList<>();
if (isTest) {
ClassLoader loader = this.getClass().getClassLoader();
String file = loader.getResource("endpointOne.txt");
...
someData = someMethodReadingResourceFile();
}
else {
someData = someMethodReadingFromAPI();
}
}
So, from JUnit #Test I set isTest as true and from runtime false.
This does not sound elegant to me.
Is there a clever way?

If you are writing JUnit test its better to use Mockito or PowerMockito (or any other librbrary for that matter) to mock the API call. Thats the cleaner way of doing JUnit tests.
For example if you have :
private void loadDataFromEndpointOne() {
someData = someMethodReadingFromAPI();
}
Mock it like this from your test class :
Mockito.when(mockedClass.loadDataFromEndpointOne()).thenReturn(someDummyDataForTest);
For more info you can refer Mockito's doc.

Related

Debugging ignored tests in testng?

I have a maven Java project in Intellij IDEA community. The TestNg version is very old i.e. 6.9.5 and I simply cannot update it. I have 6 TestNg test methods in a class. Only 5/6 of these methods use data provider methods, all of which are in one DataProvider class.
When I run the test class, only the method without data provider (say test_5) runs successfully. The others are marked as "test ignored". Moreover, when I comment or disable test_5, then all the other tests run. Can I make testng give a detailed reason for ignoring tests ?
Here is brief information about my project. I can't give the full code.
public class MyUtilityClass {
public class MyUtilityClass(){
//Load data from property files and initialize members, do other stuff.
}
}
public class BaseTest {
MyUtilityClass utilObj = new MyUtilityClass();
//do something with utilObj, provide common annotated methods for tests etc.
}
public class TestClass extends BaseTest {
#BeforeClass
public void beforeMyClass(){
//Get some data from this.utilObj and do other things also.
}
#Test(dataProvider = "test_1", dataProviderClass = MyDataProvider.class)
test_1(){}
#Test(dataProvider = "test_2", dataProviderClass = MyDataProvider.class)
test_2(){}
...
//test_5 was the only one without data provider.
test_5(){}
#Test(dataProvider = "test_6", dataProviderClass = MyDataProvider.class)
test_6(){}
}
public class MyDataProvider {
MyUtilityClass utilObj = new MyUtilityClass();
//do something with utilObj besides other things.
}
Your tests need to end in exactly the same environment in which they started.
You gave nary a clue as to what your code is like, but I can say that it is almost certainly either a database that is being written to and not reverted or an internal, persistent data structure that is being modified and not cleared.
If the tests go to the database, try enclosing the entire test in a transaction that you revert at the end of the test. If you can't do this, try mocking out the database.
If it's not the DB, look for an internal static somewhere, either a singleton pattern or a static collection contained in an object. Improve that stuff right out of your design and you should be okay.
I could give you more specific tips with code, but as is--that's about all I can tell you.
I solved my problem. Test_5 is the only test method which does not have a data provider. So, I provided a mock data provider method for it.

How can I write valid JUnit tests when mocking a filepath?

I am trying to write some JUnit tests for a set of methods which use some REST services on the web.
In general, within my methods, I am providing a filepath and a configuration as a parameter, but I expect things will get more complicated as I progress.
For right now, what are the best ways for me to write JUnit tests for the likes of :
public Answers changeFileToAnswer(String filePath, String mediaType) {
File document = new File(filePath);
Answers answers = restService.changeFileToAnswer(document, mediaType);
return answers;
}
What kind of Unit tests can I write for a simple class like this? Testing the answers object would be an integration tests, since an external call is made here, right? What is good practise here? Is there a way to mock the filepath being passed in as a parameter?
Notes -
This method is from a REST interface which will later be exposed through a GUI. I am currently testing it with POST calls from POSTman. Due to this, I am passing in a string for the filePath rather than a file object (as I could not post this to my server).
Thanks.
The test is not necessary to be integration. Your restService need to be mock or fake, so there is no real external call.
For mocking filePath you can use JUnit TemporaryFolder.
public class TestClass{
#Rule
private TemporaryFolder folder = new TemporaryFolder();
#Test
public void testMethod(){
File tempFile = folder.newFile("myfile.txt");
classUnderTest.changeFileToAnswer(file.getPath(), mediaType);
}
}
This rule will create a real file in file system which will be removed when tests finish execution.
UPD: You might also want to take a look at jimfs

Junit testing in a Spring / Maven project

I have a problem writing a Junit testcase for a Spring project. Its about the following method;
boolean doesUserIdExist(String userId){
if(userRepository.findOne(userId.toLowerCase()) != null) {
throw new userAlreadyExistsException("User with id: " + userId + " already exists")
return false;
}else{
return true;
}
}
Now in my jUnit I have something written like this..:
void compareDuplicateUserIdTest (){
UserService UserService = new UserService();
String lowercase = "test";
String uppercase = "Test";
boolean result = userService.doesUserIdExist(lowercase);
//Check the boolean result if its true
}
Since im using the findOne method it means that i'd have to check the String = "test" against the DB userId = "test". This is not the right way since it should work standalone without any records in the MongoDB database.
Now i've been reading about a framework like mockito to test this, but isn't this "too much" for such a simple method check? Can I remove the findOne part and just compare the strings?
You are facing a very common problem for unit testing where databases should not be involved (that would be integration testing), so... here is where Mockito is a great tool to use.
Using Mockito allows you to mock your database results and continue with the regular flow of your method, so you could do something like this:
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.when;
#RunWith(MockitoJUnitRunner.class)
public class UserService_doesUserIdExistTests
{
#Mock
private UserRepository userRepository;
#InjectMocks
private UserService userService;
#Test
void compareDuplicateUserIdTest() {
String lowercase = "test";
// Mocking the response for your method that uses external dependencies
when(userRepository.findOne(lowercase)).thenReturn(true); // You can mock the response you want using .thenReturn(...)
// Test your userService method (you can also debug it if needed)
boolean result = userService.doesUserIdExist(lowercase);
//Check the boolean result if its true
assertTrue(result);
}
}
I have not tested the code but shows the idea of testing userService.doesUserIdExist(...) method as a unit. Also this is quite helpful when you need to learn by debugging code.
No, it is not too much. The idea of Unit tests is to test method behaviour based on different inputs and insure it behaves as expected. It also documents your expectations and makes refactoring much less painful.
Imagine in the future somebody (may be even you) will decide to remove userRepository.findOne from doesUserExist method. Your unit test will fail and then the developer will have to figure out if the tests need to be changed due to rafactoring or the refactoring needs to be fixed.
I am not even sure what you'll be testing if you remove findOne method and how you are planning to do that.
Mockito and Spring make mocking really simple. All you need to do is define and initiate mock userRepository and then define the behaviour based on the input.

Junit Testing Mocking a File Operation

I have a piece of code similar to the below that I have been asked to Junit test. We are using Junit, EasyMock and Spring Framework. I've not done much Junit testing, and am a bit lost as to how I can mock the below.
Basically the path to the file as in the directory it will be in, won't exist when I'm writing or running the test on my machine. I'm wondering is there a way to mock the object to a temporary location as the location it will actually run with is guaranteed to exist and be tested during integration testing.
However I'm wondering would it even be wise to do so or should this be tested when it is integrated with the rest of the project when the directory will actually exist.
Any help appreciated, as Junit testing is completely new to me. I've looked around but can't see how to do what I want (might be a good hint that I shouldn't be doing it :P).
String fileName = pathToFileName;
File file = new File(fileName);
if (file.exists()) {
FileUtil.removeLineFromFile(file, getValueToRemove(serialNumber));
}
First option is to inject the file into your class where you can just inject the mock directly. Usually the better option, but not always elegant or feasible.
I've gotten some mileage out of these things by creating a protected wrapper function for problematic objects such as this. In your class under test:
protected File OpenFile(String fileName) { return new File(filename;}
In the test class:
File file = EasyMock.createNiceMock(File.class);
private MyClass createMyClass() {
return new MyClass() {
#Override protected File OpenFile(String fileName) { return file; }
};
}
#Test public testFoo() {
EasyMock.expect(file.exists()).andStubReturn(true);
//...
MyClass myClass=createMyClass();
// ...
}
If you need, you can save off the construction parameters (fileName) in this case for validation.

How to write automated unit tests for java annotation processor?

I'm experimenting with java annotation processors. I'm able to write integration tests using the "JavaCompiler" (in fact I'm using "hickory" at the moment). I can run the compile process and analyse the output. The Problem: a single test runs for about half a second even without any code in my annotation processor. This is way too long to using it in TDD style.
Mocking away the dependencies seems very hard for me (I would have to mock out the entire "javax.lang.model.element" package). Have someone succeed to write unit tests for an annotation processor (Java 6)? If not ... what would be your approach?
This is an old question, but it seems that the state of annotation processor testing hadn't gotten any better, so we released Compile Testing today. The best docs are in package-info.java, but the general idea is that there is a fluent API for testing compilation output when run with an annotation processor. For example,
ASSERT.about(javaSource())
.that(JavaFileObjects.forResource("HelloWorld.java"))
.processedWith(new MyAnnotationProcessor())
.compilesWithoutError()
.and().generatesSources(JavaFileObjects.forResource("GeneratedHelloWorld.java"));
tests that the processor generates a file that matches GeneratedHelloWorld.java (golden file on the class path). You can also test that the processor produces error output:
JavaFileObject fileObject = JavaFileObjects.forResource("HelloWorld.java");
ASSERT.about(javaSource())
.that(fileObject)
.processedWith(new NoHelloWorld())
.failsToCompile()
.withErrorContaining("No types named HelloWorld!").in(fileObject).onLine(23).atColumn(5);
This is obviously a lot simpler than mocking and unlike typical integration tests, all of the output is stored in memory.
You're right mocking the annotation processing API (with a mock library like easymock) is painful. I tried this approach and it broke down pretty rapidly. You have to setup to many method call expectations. The tests become unmaintainable.
A state-based test approach worked for me reasonably well. I had to implement the parts of the javax.lang.model.* API I needed for my tests. (That were only < 350 lines of code.)
This is the part of a test to initiate the javax.lang.model objects. After the setup the model should be in the same state as the Java compiler implementation.
DeclaredType typeArgument = declaredType(classElement("returnTypeName"));
DeclaredType validReturnType = declaredType(interfaceElement(GENERATOR_TYPE_NAME), typeArgument);
TypeParameterElement typeParameter = typeParameterElement();
ExecutableElement methodExecutableElement = Model.methodExecutableElement(name, validReturnType, typeParameter);
The static factory methods are defined in the class Model implementing the javax.lang.model.* classes. For example declaredType. (All unsupported operations will throw exceptions.)
public static DeclaredType declaredType(final Element element, final TypeMirror... argumentTypes) {
return new DeclaredType(){
#Override public Element asElement() {
return element;
}
#Override public List<? extends TypeMirror> getTypeArguments() {
return Arrays.asList(argumentTypes);
}
#Override public String toString() {
return format("DeclareTypeModel[element=%s, argumentTypes=%s]",
element, Arrays.toString(argumentTypes));
}
#Override public <R, P> R accept(TypeVisitor<R, P> v, P p) {
return v.visitDeclared(this, p);
}
#Override public boolean equals(Object obj) { throw new UnsupportedOperationException(); }
#Override public int hashCode() { throw new UnsupportedOperationException(); }
#Override public TypeKind getKind() { throw new UnsupportedOperationException(); }
#Override public TypeMirror getEnclosingType() { throw new UnsupportedOperationException(); }
};
}
The rest of the test verifies the behavior of the class under test.
Method actual = new Method(environment(), methodExecutableElement);
Method expected = new Method(..);
assertEquals(expected, actual);
You can have a look at the source code of the Quickcheck #Samples and #Iterables source code generator tests. (The code is not optimal, yet. The Method class has to many parameters and the Parameter class is not tested in its own test but as part of the Method test. It should illustrate the approach nevertheless.)
Viel Glück!
jOOR is a small Java reflection library that also provides simplified access to the in-memory Java compilation API in javax.tool.JavaCompiler. We added support for this to unit test jOOQ's annotation processors. You can easily write unit tests like this:
#Test
public void testCompileWithAnnotationProcessors() {
AProcessor p = new AProcessor();
try {
Reflect.compile(
"org.joor.test.FailAnnotationProcessing",
"package org.joor.test; " +
"#A " +
"public class FailAnnotationProcessing { " +
"}",
new CompileOptions().processors(p)
).create().get();
Assert.fail();
}
catch (ReflectException expected) {
assertFalse(p.processed);
}
}
The above example has been taken from this blog post
I was in a similar situation, so I created the Avatar library. It won't give you the performance of a pure unit test with no compilation, but if used correctly you shouldn't see much of a performance hit.
Avatar lets you write a source file, annotate it, and convert it to elements in a unit test. This allows you to unit test methods and classes which consume Element objects, without manually invoking javac.
I ran into the same problem awhile ago and found this question. Although the other answers provided are decent, I felt that that there was still room for improvement. Based on the other answers for this question, I created Elementary, a suite of JUnit 5 extensions that provide a real annotation processing environment for unit tests.
Most libraries test annotation processors by running them. However, most annotation processors are pretty complex and broken into more fine-grained components. It is not feasible to test individual components by running the annotation processor. Instead, we make the annotation processing environment available to these tests.
The following code snippet illustrates how to test a Lint component:
import com.karuslabs.elementary.junit.Cases;
import com.karuslabs.elementary.junit.Tools;
import com.karuslabs.elementary.junit.ToolsExtension;
import com.karuslabs.elementary.junit.annotations.Case;
import com.karuslabs.elementary.junit.annotations.Introspect;
import com.karuslabs.utilitary.type.TypeMirrors;
#ExtendWith(ToolsExtension.class)
#Introspect
class ToolsExtensionExampleTest {
Lint lint = new Lint(Tools.typeMirrors());
#Test
void lint_string_variable(Cases cases) {
var first = cases.one("first");
assertTrue(lint.lint(first));
}
#Test
void lint_method_that_returns_string(Cases cases) {
var second = cases.get(1);
assertFalse(lint.lint(second));
}
#Case("first") String first;
#Case String second() { return "";}
}
class Lint {
final TypeMirrors types;
final TypeMirror expectedType;
Lint(TypeMirrors types) {
this.types = types;
this.expectedType = types.type(String.class);
}
public boolean lint(Element element) {
if (!(element instanceof VariableElement)) {
return false;
}
var variable = (VariableElement) element;
return types.isSameType(expectedType, variable.asType());
}
}
By annotating the test class with #Introspect and test cases with #Case, we can declare test cases in the same file as the tests. The corresponding Element representation of the test cases can be retrieved by a test using Cases.
If anyone is interested, I wrote an article, The Problem with Annotation Processors that details the problems with unit testing annotation processors.
I have used http://hg.netbeans.org/core-main/raw-file/default/openide.util.lookup/test/unit/src/org/openide/util/test/AnnotationProcessorTestUtils.java though this is based on java.io.File for simplicity and so has the performance overhead you complain about.
Thomas's suggestion of mocking the whole JSR 269 environment would lead to a pure unit test. You might instead want to write more of an integration test which checks how your processor actually runs inside javac, giving more assurance it is correct, but merely want to avoid disk files. Doing this would require you to write a mock JavaFileManager, which is unfortunately not as easy as it seems and I have no examples handy, but you should not need to mock other things like Element interfaces.
An option is to bundle all tests in one class. Half a second for compiling etc. is then a constant for a given set of tests, the real test time for a test is negligible, I assume.

Categories

Resources