I have a test case I'm trying to finish. It should try to find location ABC, but that doesn't actually exist in the DB. Essentially, it should not load the data I'm trying to find. I've tried a bunch of things, and haven't figured it out yet. Here is my code:
#Test
public void testFindByInvalidLocABC() {
System.out.println("findByInvalidLocABC");
Storage result = StorageFacadeTest.facade.findByLoc("ABC");
assertNotNull(result);
assertEquals("NOK-0000001402", result.getId());
assertEquals("ABC", result.getLoc());
}
Any suggestions is greatly appreciated!
I have a test case I'm trying to finish. It should try to find
location ABC, but that doesn't actually exist in the DB
To ensure that data be present or not present during test executions, you cannot rely on a applicative or shared database.
Automated tests have to be repeatable. Otherwise, these will be reliable today but useless and error prone tomorrow.
So I encourage you to clean/populate a test database( or schema) before the tests be executed.
Besides, as others commented, your test doesn't look like a "not found" scenario. You assert the retrieved Storage content. It makes no sense.
It should rather look like :
#Test
public void findByLoc_with_invalidLoc_returns_null() {
Storage result = StorageFacadeTest.facade.findByLoc("ABC");
assertNull(result);
}
Some improvements for your unit test:
1) Returning Optional instead of null in the method under test is probably better but you don't use it in your actual implementation. So I follow it in my example.
2) System.out is really not advised in the test code.
3) The test prefix in the test method is not advised either. It is a legacy way as Java annotations didn't exist.
Related
I have this method that I am using in a NetBeans plugin:
public static SourceCodeFile getCurrentlyOpenedFile() {
MainProjectManager mainProjectManager = new MainProjectManager();
Project openedProject = mainProjectManager.getMainProject();
/* Get Java file currently displaying in the IDE if there is an opened project */
if (openedProject != null) {
TopComponent activeTC = TopComponent.getRegistry().getActivated();
DataObject dataLookup = activeTC.getLookup().lookup(DataObject.class);
File file = FileUtil.toFile(dataLookup.getPrimaryFile()); // Currently opened file
// Check if the opened file is a Java file
if (FilenameUtils.getExtension(file.getAbsoluteFile().getAbsolutePath()).equalsIgnoreCase("java")) {
return new SourceCodeFile(file);
} else {
return null;
}
} else {
return null;
}
}
Basically, using NetBeans API, it detects the file currently opened by the user in the IDE. Then, it loads it and creates a SourceCodeFile object out of it.
Now I want to unit test this method using JUnit. The problem is that I don't know how to test it.
Since it doesn't receive any argument as parameter, I can't test how it behaves given wrong arguments. I also thought about trying to manipulate openedProject in order to test the method behaviour given some different values to that object, but as far as I'm concernet, I can't manipulate a variable in JUnit that way. I also cannot check what the method returns, because the unit test will always return null, since it doesn't detect any opened file in NetBeans.
So, my question is: how can I approach the unit testing of this method?
Well, your method does take parameters, "between the lines":
MainProjectManager mainProjectManager = new MainProjectManager();
Project openedProject = mainProjectManager.getMainProject();
basically fetches the object to work on.
So the first step would be to change that method signature, to:
public static SourceCodeFile getCurrentlyOpenedFile(Project project) {
...
Of course, that object isn't used, except for that null check. So the next level would be to have a distinct method like
SourceCodeFile lookup(DataObject dataLookup) {
In other words: your real problem is that you wrote hard-to-test code. The "default" answer is: you have to change your production code, to make easier to test.
For example by ripping it apart, and putting all the different aspects into smaller helper methods.
You see, that last method lookup(), that one takes a parameter, and now it becomes (somehow) possible to think up test cases for this. Probably you will have to use a mocking framework such as Mockito to pass mocked instances of that DataObject class within your test code.
Long story short: there are no detours here. You can't test your code (in reasonable ways) as it is currently structured. Re-structure your production code, then all your ideas about "when I pass X, then Y should happen" can work out.
Disclaimer: yes, theoretically, you could test the above code, by heavily relying on frameworks like PowerMock(ito) or JMockit. These frameworks allow you to contol (mock) calls to static methods, or to new(). So they would give you full control over everything in your method. But that would basically force your tests to know everything that is going on in the method under test. Which is a really bad thing.
I have three JUnit tests, which are shown below. These test all succeed if they are executed individually i.e. commenting out the two other tests and only executing one.
However, if I execute all three tests uncommented then "testOrderDatabaseReturnsOrdersCorrectly" produces an error and "testOrderDatabaseRemovesOrdersCorrectly" fails.
I really don't understand why this is happening. I'm using #Before to set up before each test, so the conditions for all three tests should be the same? Why are some of them failing when they work fine individually?
#Before
public void setup()
{
sys = new OrderSystem();
sys.getDb().clearDb();
}
#Test
public void testOrderDatabaseAddsOrders()
{
sys.getDb().clearDb();
sys.createOrder(25);
assertEquals(sys.getDb().getDbArrayList().size(), 1);
sys.createOrder(30);
assertEquals(sys.getDb().getDbArrayList().size(), 2);
sys.createOrder(35);
assertEquals(sys.getDb().getDbArrayList().size(), 3);
}
#Test
public void testOrderDatabaseRemovesOrdersCorrectly()
{
sys.createOrder(25);
assertEquals(sys.getDb().getDbArrayList().size(), 1);
sys.removeOrder("BRICK1");
assertEquals(sys.getDb().getDbArrayList().size(), 0);
}
#Test
public void testOrderDatabaseReturnsOrdersCorrectly()
{
System.out.println("Size of db: " + sys.getDb().getDbArrayList().size());
sys.createOrder(25);
System.out.println("Size of db: " + sys.getDb().getDbArrayList().size());
BrickOrder o = sys.getOrder("BRICK1");
assertEquals(o.getNumberOfBricks(), 25);
}
However, if I execute all three tests uncommented then "testOrderDatabaseReturnsOrdersCorrectly" produces an error and "testOrderDatabaseRemovesOrdersCorrectly" fails.
Your problem most likely is that the results from one of the test methods is not being cleared when the next test method is run and they are clashing. Maybe you are using a memory database like H2 which is not being fully cleared even though you are calling sys.getDb().clearDb();?
Couple of ways you can verify this:
First put a System.out.println() message in setup() to make sure it is being called before each method.
At the start of your test methods, do a lookup in your database to see if there are results there to verify the clearDb() did something. I suspect you will see that it isn't working fully.
Change the test methods to use non overlapping tables or to use non overlapping data to see if that works. For example, create a int orderNumber field and do a ++ on it in each test method to make sure you are using a new order. This is a work around of course. It would be better to understand why clear isn't doing what you want.
How to fix this is a more complicated problem that depends on what actually is backing your db. Maybe you just have some bugs in your clearDb() method. I mention H2 because even if you setup a brand new database connection, the old one never is destroyed and will be reused. If it is a SQL database, fully dropping the tables and recreating them is one thing that forces even a persistent memory database like H2 to clear its stuff.
Hope this helps.
I have figured out what was causing the errors and strange test behaviour.
I had a field variable which was declared static. For some reason this was not being reset before each test, even though the sys variable was being reset each time. When I removed the static declaration for this variable all of the tests succeeded.
Here is a snippet of my code. I want to force call the catch block with WakeupException.
public void run() {
try {
try {
while (true) {
LOGGER.logp(Level.INFO, CLASS_NAME, "run()", "Attempting to Poll");
ConsumerRecords<String, String> records = consumer.poll(10000);
if (records.count() == 0) {
LOGGER.logp(Level.INFO, CLASS_NAME, "run()", "No Response. Invalid Topic");
break;
}
else if(records.count()>0) {
LOGGER.logp(Level.INFO, CLASS_NAME, "run()", "Response Received");
}
}
}
} catch (WakeupException e) {
consumer.close();
}
}
Here is what I tried:
#Test(expected = WakeupException.class)
public void failRun() throws WakeupException, IOException {
KafkaConsumerForTests consumerThread3;
consumerThread3 = Mockito.mock(KafkaConsumerForTests.class);
doThrow(new WakeupException()).when(consumerThread3).run();
//Mockito.when(consumerThread2.run()).thenThrow(new WakeupException());
consumerThread3.run();
}
I just want to call the WakeupException so that I get line coverage for that block of code. What would I do. This is a void method by the way. I'm open to suggestions involving PowerMock as well.
After seeing the code, I am quite sure that the call we want to mock is consumer.poll(...). I am not an expert in using Kafka so take everything from here with a grain of salt. Seeing that consumer is an attribute of the class under test, it should be possible to inject a mocked instance into the class under test and throw the WakeupException we need. Instead of (or additional to - your decision) the class under test, we create a(n additional) mock of the consumer and mock its poll(...)-method to throw the desired WakeupException when called. Instead of mocking the call to consumerThread3.run(), we mock the call to consumer.poll(...).
A remark on your question: "I just want to call the WakeupException so that I get line coverage" - This should never be the reason to write a test. A test should test behaviour. If there is no behaviour to test (which is rarely the case), do not write a test.
OP edited the question and added some additional information. I am quite confident that the first paragraph of this post should answer the question. The other paragraphs were written before OP added the relevant code in the try-block. They are written on a more abstract level. The interested reader may read them, but this is not necessary to understand the answer.
お楽しみください! - Please enjoy!
We want to verify the behaviour of the catch-block. In productive code, something in the try-block would throw the corresponding Exception triggering the catch-block. Thus, in order to test the catch-block, we should mock something in the try-block to throw said Exception.
If mocking a call within the block seems impossible, that may be due to the fact that the code was not developed test-driven. You see, an upside of Test-Driven Development is that you intrinsically generate testable code. If we are stuck with untestable/hard to test code, w ehave two (or maybe three) options:
Leave it as is, do not test it. This can be a valid answer if there is no behaviour to test.
Rewrite the code, make it testable. Depending on the structure of your project this could take from five minutes up to 2 weeks or more. Hard to say without knowing the codebase
Use unconventional tools. Normal mocking frameworks like Mockito have certain limittations, e.g. for Mockito mocking of static or final methods is not supported. Other tools, like PowerMock, aim to eliminate those limitations. But be warned: PowerMock operates on bytecode level. This means that
we are not necessarily testing the bytecode we use in production
this can screw with other tools, e.g. JaCoCo.
Those tools should be your last resort only and used sparsely.
I want to test that a specific method produces the expected result, but to do that I need to manipulate the input in the test as well.
class ToTest {
public String produceResponse(String input) {
// ....
encryptedIds = encryptIds(input)
output = doStuff(input, encryptedIds)
}
public encryptIds(input) {
....
}
}
In my test I need to check that produceResponse actually produces the expected response.
in order to do that I have to encrypt the ids in the input.
My question is: should I rewrite encryptIds in the test (so that I would have more controller on the result) or should I call encryptIds from the class itself.
Is there a better approach to solve this? I don't like that in my test I know what happens in the specific flow.
If I understand correctly, you would like to test produceResponse() with known encryptedIds as input.
You could do that without refactoring the code, but it would probably be a good idea to refactor it, so that's what I'm going to explain:
class ToTest {
private IdEncryptor encryptor;
public ToTest(IdEncryptor encryptor) {
this.encryptor = encryptor;
}
public String produceResponse(String input) {
String[] encryptedIds = encryptor.encryptIds(input);
return doStuff(input, encryptedIds);
}
}
Now you can unit-test IdEncryptor to test that it produces correct encrypted IDs based on a String input.
And to test the ToTest class, you can mock the IdEncryptor so that whatever the input it receives, it produces the encryptedIds you desire. For example with mockito:
IdEncryptor mockEncryptor = mock(IdEncryptor.class);
when(mockEncryptor.encryptIds(any(String.class)).thenReturn(new String[] {"a", "b"});
ToTest toTest = new ToTest(mockEncryptor);
String response = toTest.produceResponse("input");
// expect that the response is what you expect given "a", "b" as input of doStuff()
Never copy any production code into the unit test as it will get outdated at some point.
If both methods are public, they are part of the public API, so:
you should first unit test the correct behavior of the encryptIds(String) method
then unit test the produceResponse(String) method which will internally use the already tested encryptIds(String) method
If encryptIds(String) would not be part of the public API:
then it is internal implementation and helper method which is not unit testable
produceResponse(String) is then responsible for encryption as a side-effect:
you can still test it if you mark it package private (no modifier)
you can also change the implementation of the encryptIds(String) only for testing purposes
Is encrypting id's something that is integral to your system or not? As it stands this class takes some input and produces some output and as far as your test is concerned this is what's important, no more, no less.
What is the impact of not performing the encryption? If your doStuff method will just fail if it doesn't happen then it is an internal detail to your class-under-test and I wouldn't have the tests care about it at all. If it's a step that absolutely must be performed then I would refactor the code to verify that it absolutely has happened, maybe using a mock as #jb-nizet answered.
As for the general case of duplicating production code in tests, as #Crazyjavahacking stated you should not do this, but I have no issue with using production code from a test- maybe not at a unit level but definitely the higher up the system I go, e.g. when testing writing to a DB I will use the reading code to verify it's happened correctly, but will also have independent tests to verify the reading path as well
I have Struts 1 action and want to test it in isolation.
What this action do is as follows:
load data using parameters from request
build xml-based representation of this data
send this response directly to client
I use jMock for testing but have one doubt here.
My first test is
public void shouldActionInvocationPrintValidResponse() {
ProcessingAction action = new ProcessingAction();
DBService service = mock(DBService.class);
List records = new ArrayList();
when(service.loadData()).thenReturn(records);
ResponseBuilder builder = mock(ResponseBuilder.class);
when(builder.buildResponse(records)).thenReturn("fake response");
action.execute(null, null, null, null);
assertEquals("fake response", writer.getContentWritten());
}
And my prod code evaluated to this:
public String execute(...) {
List recordsList = service.loadData();
String response = responseBuilder.buildResponse(recordsList);
response.getWriter().print(response);
}
My doubt here is if such test isn't too big here. I check whole succesful flow here. Shouldn't there be separate tests for checking every single dependency call in their own tests?
I wonder because I had troubles with this test's name. My ideas at the beginning were something like
shouldFetchDataThenFormatThemAndSendResponse
As this is all the tests does, the name shows it probably does too much (look at the "and" e.g. in the test name)
And should I have whole test written at once, or just add dependencies calls step-by-step?
EDIT:
Detailed code for test and action provided.
I think you are on the right track. shouldFetchDataThenFormatThemAndSendResponse This says it all. In your test naming you are talking about implementation details. This is how your first test should have been written.
ProcessingAction action = new ProcessingAction();
Response response = action.execute();
assertEquals(true, response.IsValid);
Try: shouldGetResponseWhenActionExecuted.
Now you can look at how to get a response when executing an action.
I would bet you dollars to donuts that you didn't TDD this.
Remember: Intent over Implementation! Stop showing your crusty underwear.
It is hard to answer your question without seeing the code however I will give it a stab. For the test to be a Unit test, it should not exercise code other than the code in the class under test. If you have mocked every other class that the action calls and what you are verifying is only being done within the class under test, then no the test is not too big. I have written unit tests that have a large number of verification statements because all the things happen in the class under test due to the single invocation of the method.
My unit test rules are:
1. Exercise code only in the class under test
2. Only enter the method under test once per test method
I agree with John B.
Also, if you use the Mock Test Runner and write it correctly, you may not need an assertion.