Failing unit test with mockito.mockStatic - java

So, I'm writing a junit test and I can't seem te figure out why it is failing. I'm using Mockito.mockStatic in order to mock InetAddres.class. Running the unit tests all at once fails. Running them separately succeeds. I understand static blocks are initialized once. What I can't seem to figure out is why class Host is not reinitialized with every unit test. Any help is appreciated
J
Here is my code:
import org.junit.jupiter.api.Test;
import org.mockito.MockedStatic;
import org.mockito.Mockito;
import java.net.InetAddress;
import java.net.UnknownHostException;
import static org.assertj.core.api.Assertions.assertThat;
class HostTest {
#Test
void testLocalhost() {
try (MockedStatic<InetAddress> inetAddressMockedStatic = Mockito.mockStatic(InetAddress.class)) {
InetAddress inetAddress = Mockito.mock(InetAddress.class);
Mockito.when(inetAddress.getHostName()).thenReturn("LOCALHOST");
inetAddressMockedStatic.when(InetAddress::getLocalHost).thenReturn(inetAddress);
assertThat(Host.getLOCALHOST()).isEqualTo("LOCALHOST");
Mockito.reset(inetAddress);
}
}
#Test
void testIP() {
try (MockedStatic<InetAddress> inetAddressMockedStatic = Mockito.mockStatic(InetAddress.class)) {
InetAddress inetAddress = Mockito.mock(InetAddress.class);
Mockito.when(inetAddress.getHostAddress()).thenReturn("127.0.0.1");
inetAddressMockedStatic.when(InetAddress::getLocalHost).thenReturn(inetAddress);
assertThat(Host.getIP()).isEqualTo("127.0.0.1");
}
}
#Test
void testUnkownHostExceptionIP() {
try (MockedStatic<InetAddress> inetAddressMockedStatic = Mockito.mockStatic(InetAddress.class)) {
inetAddressMockedStatic.when(InetAddress::getLocalHost).thenThrow(UnknownHostException.class);
assertThat(Host.getIP()).isEqualTo("Unkown ip");
}
}
#Test
void testUnkownHostExceptionLocalhost() {
try (MockedStatic<InetAddress> inetAddressMockedStatic = Mockito.mockStatic(InetAddress.class)) {
inetAddressMockedStatic.when(InetAddress::getLocalHost).thenThrow(UnknownHostException.class);
assertThat(Host.getLOCALHOST()).isEqualTo("Unkown hostname");
}
}
}
import java.net.InetAddress;
import java.net.UnknownHostException;
public class Host {
private static String LOCALHOST;
private static String IP;
static {
try {
InetAddress localhost = InetAddress.getLocalHost();
LOCALHOST = localhost.getHostName();
IP = localhost.getHostAddress();
} catch (UnknownHostException e) {
LOCALHOST = "Unkown hostname";
IP = "Unkown ip";
}
}
public static String getLOCALHOST() {
return LOCALHOST;
}
public static String getIP() {
return IP;
}
}

The static initializer is only executed once, when the class is loaded. This means it will only run for the first test case using the Host class.
In your example, once testLocalhost is run, the class is used in the line Host.getLOCALHOST(), by which point its initializer has been executed. It never runs again throughout the rest of the unit tests.
If you switch the order of these test cases, you'll get a different result.
Judging by your test cases, there's a few things you could do to make the code match your expectations. Since the IP and the host name will change throughout the execution of your program, they shouldn't be static members set in the static initializer block.
Get rid of shared state. Setting aside concurrency and memory visibility, static members will be visible to all instances of the class. Omit the static keyword and make these into regular fields
public class Host {
private final String hostName;
private final String ip;
// Constructor, use this to build new instances
public Host(String hostName, String ip) {
this.hostName = hostName;
this.ip = ip;
}
// No longer static, this is now an instance method
public getHostName() {
return this.hostName;
}
public getIp() {
return this.ip;
}
}
Build instances of your class, passing arguments to the constructor to customize its behaviour.
// Host.getIp(); // If IP and host name can vary, don't make them static
InetAddress localhost = InetAddress.getLocalHost();
// build a new instance of Host, provide the relevant data at construction time
Host testedHost = new Host(localhost.getHostName(), localhost.getHostAddress());
// call the instance method, this doesn't affect your other tests
assertThat(testedHost.getIp()).is(someIp);
// at this point, the Host instance you created may be garbage-collected to free memory (you don't need to do that yourself)
Now every test case will be independent from the others. Just create a new instance of Host every time you need one.
Get rid of static mocks. notice how the InetAddress method invocations were moved outside the Host class. By passing them through the constructor, you make the code easier to test. Inversion of control is achieved.
Instead of a public constructor, you could use a factory method. Bottom line is that if you want to have the class change its behaviour, it's usually better to create new instances and encapsulate any state.
Static classes and members are better suited for things like immutable contants that won't change throughout the execution of your program, or utility methods that don't rely on any internal state, i.e. pure functions.

Related

Can't connect to a testcontainer Postgres instance

I've created a Postgres instance using testcontainers. The container starts but I cannot access it.
I have tried connecting at the containerized DB using DBeaver.
In the eclipse console everything seems fine:
01:29:34.662 [main] DEBUG com.github.dockerjava.core.command.AbstrDockerCmd - Cmd: com.github.dockerjava.core.command.CreateContainerCmdImpl#73386d72[name=,hostName=,domainName=,user=,attachStdin=,attachStdout=,attachStderr=,portSpecs=,tty=,stdinOpen=,stdInOnce=,env={POSTGRES_USER=test,POSTGRES_PASSWORD=test,POSTGRES_DB=ASIGDB_TEST}
Here is my code:
public class CustomPostgresContainer extends PostgreSQLContainer<CustomPostgresContainer>{
private static final String IMAGE_VERSION = "postgres:9.6";
private static CustomPostgresContainer customPostgresContainer;
private static final int EXPOSED_PORT = 5555;
private static final String DB_NAME = "ASIGDB_TEST";
private static final String DB_USER= "test";
private static final String DB_PASSWORD= "test";
public CustomPostgresContainer() {
super(IMAGE_VERSION);
}
public static CustomPostgresContainer getCustomPostgresContainerInstance() {
if(customPostgresContainer == null) {
return extracted().withExposedPorts(EXPOSED_PORT)
.withDatabaseName(DB_NAME)
.withUsername(DB_USER)
.withPassword(DB_PASSWORD);
}
return customPostgresContainer;
}
private static CustomPostgresContainer extracted() {
return new CustomPostgresContainer();
}
#Override
public void start() {
super.start();
}
#Override
public void stop() {
//do nothing, JVM handles shut down
}
}
I get:
Connection to localhost:5555 refused. Check that the hostname and port are correct and that the postmaster is accepting TCP/IP connections.
Does anyone know what is going on?
According to this link, withExposedPorts() --> this exposed port number is from the perspective of the container.
From the host's perspective Testcontainers actually exposes this on a random free port. This is by design, to avoid port collisions that may arise with locally running software or in between parallel test runs.
Because there is this layer of indirection, it is necessary to ask Testcontainers for the actual mapped port at runtime. This can be done using the getMappedPort method, which takes the original (container) port as an argument:
Integer firstMappedPort = container.getMappedPort(yourExposedPort);<br/>
Try to connect with DBeaver to the port that appears first.

Second main() class does not see variables initialized in first main() class

I'm developing an application that requires two main() classes, first one for the actual application, and a second one for the JMX connectivity and management. The issue I'm facing is even after ensuring the first main() is executed and initializes the variables, when the second main() runs but does not see those variables and throws null exception.
Application main():
public class GatewayCore {
private static Logger logger = Logger.getLogger(GatewayCore.class);
private static ThreadedSocketInitiator threadedSocketInitiator;**
private static boolean keepAlive = true;
//private static Thread mqConnectionManager;
public static void main(String args[]) throws Exception {
__init_system();
__init_jmx();
__init_mq();
while(keepAlive) {}
}
private static void __init_system() {
try {
logger.debug("__init_system:: loading configuration file 'sessionSettings.txt'");
SessionSettings sessionSettings = new SessionSettings(new FileInputStream("sessionSettings.txt"));
logger.info("\n" + sessionSettings);
MessageStoreFactory messageStoreFactory = new FileStoreFactory(sessionSettings);
LogFactory logFactory = new FileLogFactory(sessionSettings);
MessageFactory messageFactory = new DefaultMessageFactory();
Application sessionManager = new SessionManager();
threadedSocketInitiator = new ThreadedSocketInitiator(sessionManager, messageStoreFactory, sessionSettings, logFactory, messageFactory);
...
public static ThreadedSocketInitiator getThreadedSocketInitiator() {
return threadedSocketInitiator; }
Secondary main() class, meant to be invoked for JMX-Mbean purpose:
public class RemoteCommandLine {
private static Logger logger = Logger.getLogger(RemoteCommandLine.class);
private static final String JMX_SERVICE_URL_PREFIX = "service:jmx:rmi:///jndi/rmi://";
private static final String HOST = "localhost";
private static String PORT = "24365";
private static JMXConnectionInstance jmxConnectionInstance;
private static boolean keepAlive = true;
public static void main(String[] args) throws IOException, MalformedObjectNameException, ConfigError {
logger.debug(GatewayCore.getThreadedSocketInitiator());
...
From command line, I first run:
java -classpath etdfix.jar:slf4j-api-1.7.25.jar:mina-core-2.0.16.jar:quickfixj-all-2.0.0.jar -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=24365 -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false com.scb.etdfix.GatewayCore sessionSettings.txt
Wait for the inits to complete, ensuring threadedSocketInitiator has been assigned, then:
java -classpath etdfix.jar:slf4j-api-1.7.25.jar:mina-core-2.0.16.jar:quickfixj-all-2.0.0.jar com.scb.etdfix.JMX.RemoteCommandLine
Which ultimately throws a null pointer exception for the line:
logger.debug(GatewayCore.getThreadedSocketInitiator());
My plan is to have the first main() initialize the object, then pass to the second main() to do further method calls using the same object (it must be the same instance) when it is manually invoked. Both classes are compiled together into the same JAR. Please advise on how I can get around this issue or anything I can do to debug this further.
In fact, I'm thinking that this may not be possible as when the 2nd main() is invoked, from its POV the first main() isn't initialized. Therefore I should approach this by considering that they are two separate entities.
Each process (each java command) is completely separate, whether they run the same main() or not. This is a feature—the alternative would be to have unrelated parts of the system collide whenever they used a common utility.
That said, nothing stops you from calling GatewayCore.main() yourself (with the real command line or whatever other argument list) if you want to reuse its logic. It might be a good idea, though, to factor out the common code as another function: main() has many special responsibilities and programmers do not usually expect it to be called within a program.

How to print the whole String pool?

I wanted to print the whole string pool which contains literals and String objects added using intern() just before garbage collection.
Is there a method implicit to JDK for such operation? How can we inspect the string pool?
EDIT: The comment suggests that there may be a misunderstanding regarding what this "hack" does. It prints the strings that have been interned by (directly or indirectly) calling intern(), as described in the question. It will not print the "whole string pool", as the string pool only resides in the JVM, is filled with symbols and strings that appear during classloading and initialization, and not accessible from Java side.
NeplatnyUdaj mentioned in a comment that it might be possible to define a new java.lang.String class and sneak this into the JVM at startup. I was curious, and tried it out. And what should I say: It works!
1. Create a new project that contains the package java.lang
2. Insert a class like this into this package
package java.lang;
import java.util.LinkedHashSet;
import java.util.Set;
public class StringPool {
private static Set<String> pool = null;
public static synchronized void store(String string)
{
try
{
if (pool == null)
{
pool = new LinkedHashSet<String>();
}
pool.add(string);
}
catch (Exception e)
{
// Ignore
}
}
public static synchronized Set<String> getPool()
{
return new LinkedHashSet<String>(pool);
}
}
3. Copy & Paste the original java.lang.String class into this package. Surprisingly, this works without many problems. It will complain about a single function, namely a call to
h = sun.misc.Hashing.murmur3_32(HASHING_SEED, value, 0, value.length);
that can safely be replaced with
h = 0;
4. Change the String#intern() method of the new String class. Originally, this is a native method. It can be replaced with something like
public String intern()
{
StringPool.store(this);
return this;
}
5. Create a .JAR file from this project, and store it, for example, as newString.jar
6. Create another project with a test class that generates/contains/uses some strings. (that should be easy) and compile this class, which may be named NewStringTest
7. Launch the test program with the modified string class:
java -Xbootclasspath:newString.jar;C:\jre\lib\rt.jar NewStringTest
The StringPool#getPool() method can then be used to obtain the pool containing the interned strings.
I just tested this with the following class, which manually creates some strings, and some Swing components (which can be expected to contain some strings):
import java.lang.reflect.InvocationTargetException;
import javax.swing.JFrame;
import javax.swing.JTable;
import javax.swing.SwingUtilities;
public class NewStringTest
{
public static void main(String[] args)
{
generateSomeStrings();
System.out.println(StringPool.getPool());
}
private static void generateSomeStrings()
{
String s = "This is some test string";
for (int i=0; i<10; i++)
{
String t = s + i;
t.intern();
}
try
{
SwingUtilities.invokeAndWait(new Runnable()
{
#Override
public void run() {
JFrame frame = new JFrame();
JTable table = new JTable();
}
});
}
catch (InvocationTargetException e)
{
e.printStackTrace();
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
}
And the output is
[hashSeed, value, buf, J, D, Z, seed, segmentShift, segmentMask,
segments, state, head, tail, waitStatus, next, Ljava/lang/String;,
I, [C, [J, Ljava/util/Hashtable;, Ljava/security/PermissionCollection;,
Ljava/util/Vector;, Ljava/lang/Class;, main, This is some test string0,
This is some test string1, This is some test string2,
This is some test string3, This is some test string4,
This is some test string5, This is some test string6,
This is some test string7, This is some test string8,
This is some test string9, INSTANCE, es, , ES, sv, SE,
values, Ljava/lang/Object;, [Ljava/awt/Component;,
Ljava/awt/LayoutManager;, Ljava/awt/LightweightDispatcher;,
Ljava/awt/Dimension;, createUI, invoke, VK_F10,
VK_CONTEXT_MENU, VK_SPACE, VK_LEFT, VK_KP_LEFT,
VK_RIGHT, VK_KP_RIGHT, VK_ESCAPE, VK_C, VK_V, VK_X,
VK_COPY, VK_PASTE, VK_CUT, VK_INSERT, VK_DELETE,
VK_DOWN, VK_KP_DOWN, VK_UP, VK_KP_UP, VK_HOME, VK_END,
VK_PAGE_UP, VK_PAGE_DOWN, VK_TAB, VK_ENTER, VK_A,
VK_SLASH, VK_BACK_SLASH, VK_F2, VK_F8]
http://docs.oracle.com/javase/7/docs/api/java/lang/Object.html#finalize%28%29 , So the GC calls finalize method before clean-up any of the objects.
So the finalize method in String is also getting called. But sadly String is a final class and you cannot override it. (Why is String class declared final in Java?)
But If you really want to get this thing to be worked, then you need to create your own string object named something else, but inner behaviour will keep all the strings functions.
And for a guaranteed GC try this : http://code.google.com/p/jlibs/wiki/GarbageCollection

passing static fields to a thread

I wrote a small HTTP server in Java and I have a problem passing static variables (server configuration: port, root, etc.) to the thread that handles requests. I do not want my thread to modify these variables and if it extends the server class, it will also inherit its methods which I don't want.
I don't want to use getters for reasons of performance. If I make the static members final, I will have a problem when loading their values from the config file.
here's an example
class HTTPServer {
static int port;
static File root;
etc..
....
//must be public
public void launch() throws HTTPServerException {
loadConfig();
while (!pool.isShutdown()) {
....
//using some config here
...
try {
Socket s = ss.accept();
Worker w = new Worker(s);
pool.execute(w);
}catch () {...}
}
}
private void loadConfig(){ //reading from file};
...
other methods that must be public goes here
}
I also don't want to have the worker as nested class. It's in another package...
What do you propose?
You could put your config in a final AtomicReference. Then it can be referenced by your worker and also updated in a thread-safe manner.
Something like:
class HTTPServer {
public static final AtomicReference<ServerConf> config =
new AtomicReference(new ServerConf());
}
Make the new ServerConf class immutable:
class ServerConf {
final int port;
final File root;
public ServerConf(int port, File root) {
this.port = port;
this.root = root;
}
}
Then your worker can get a reference to the current config via HTTPServer.config.get(). Perhaps something like:
Worker w = new Worker(s, HTTPServer.config.get());
loadConfig() can set new config via something like:
HTTPServer.config.set(new ServerConf(8080, new File("/foo/bar"));
If it's not important for all your config to change at the same time, you could skip the ServerConf class and use AtomicInteger for the port setting, and AtomicReference<File> for the root.
Read the static data into a static 'sharedConfig' object that also has a socket field - you can use that field for the listening socket. When acccpet() returns with a server<> client socket, clone() the 'sharedConfig', shove in the new socket and pass that object to the server<>client worker thread. The thread then gets a copy of the config that it can erad and even modify if it wants to without afecting any other thread or the static config.

Mocking a URL in Java

We have a URL object in one of our Java classes that we want to mock, but it's a final class so we cannot. We do not want to go a level above, and mock the InputStream because that will still leave us with untested code (we have draconian test coverage standards).
I've tried jMockIt's reflective powers but we work on Macs and there are problems with the Java agent handler that I haven't been able to resolve.
So are there any solutions that do not involve using real URLs in the junit test?
Like Rob said, if what you want is to mock the connection returned from the URL, you can extend URLStreamHandler. For instance, with mockito:
final URLConnection mockUrlCon = mock(URLConnection.class);
ByteArrayInputStream is = new ByteArrayInputStream(
"<myList></myList>".getBytes("UTF-8"));
doReturn(is).when(mockUrlCon).getInputStream();
//make getLastModified() return first 10, then 11
when(mockUrlCon.getLastModified()).thenReturn((Long)10L, (Long)11L);
URLStreamHandler stubUrlHandler = new URLStreamHandler() {
#Override
protected URLConnection openConnection(URL u) throws IOException {
return mockUrlCon;
}
};
URL url = new URL("foo", "bar", 99, "/foobar", stubUrlHandler);
doReturn(url).when(mockClassloader).getResource("pseudo-xml-path");
When I have a class that can't be easily mocked because it is final (or sealed in C#), my usual route is to write a wrapper around the class and use the wrapper wherever I would use the actual class. Then I would mock out the wrapper class as necessary.
I went with the following:
public static URL getMockUrl(final String filename) throws IOException {
final File file = new File("testdata/" + filename);
assertTrue("Mock HTML File " + filename + " not found", file.exists());
final URLConnection mockConnection = Mockito.mock(URLConnection.class);
given(mockConnection.getInputStream()).willReturn(
new FileInputStream(file));
final URLStreamHandler handler = new URLStreamHandler() {
#Override
protected URLConnection openConnection(final URL arg0)
throws IOException {
return mockConnection;
}
};
final URL url = new URL("http://foo.bar", "foo.bar", 80, "", handler);
return url;
}
This gives me a real URL object that contains my mock data.
If you don't want to create a wrapper :
Register a URLStreamHandlerFactory
Make the method you want public
Mock the chain
abstract public class AbstractPublicStreamHandler extends URLStreamHandler {
#Override
public URLConnection openConnection(URL url) throws IOException {
return null;
}
}
public class UrlTest {
private URLStreamHandlerFactory urlStreamHandlerFactory;
#Before
public void setUp() throws Exception {
urlStreamHandlerFactory = Mockito.mock(URLStreamHandlerFactory.class);
URL.setURLStreamHandlerFactory(urlStreamHandlerFactory);
}
#Test
public void should_return_mocked_url() throws Exception {
// GIVEN
AbstractPublicStreamHandler publicStreamHandler = Mockito.mock(AbstractPublicStreamHandler.class);
Mockito.doReturn(publicStreamHandler).when(urlStreamHandlerFactory).createURLStreamHandler(Matchers.eq("http"));
URLConnection mockedConnection = Mockito.mock(URLConnection.class);
Mockito.doReturn(mockedConnection).when(publicStreamHandler).openConnection(Matchers.any(URL.class));
Mockito.doReturn(new ByteArrayInputStream("hello".getBytes("UTF-8"))).when(mockedConnection).getInputStream();
// WHEN
URLConnection connection = new URL("http://localhost/").openConnection();
// THEN
Assertions.assertThat(new MockUtil().isMock(connection)).isTrue();
Assertions.assertThat(IOUtils.toString(connection.getInputStream(), "UTF-8")).isEqualTo("hello");
}
}
PS : I don't know how to cancel the numbered list auto-spacing after last line
I think you can use Powermock to do this. I was able to mock URL class using PowerMock lately. Hope this helps.
/* Actual class */
import java.net.MalformedURLException;
import java.net.URL;
public class TestClass {
public URL getUrl()
throws MalformedURLException {
URL url = new URL("http://localhost/");
return url;
}
}
/* Test class */
import java.net.URL;
import junit.framework.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
#RunWith(PowerMockRunner.class)
#PrepareForTest(value = { TestClass.class })
public class TestClassTest {
private TestClass testClass = new TestClass();
#Test
public void shouldReturnUrl()
throws Exception {
URL url = PowerMockito.mock(URL.class);
PowerMockito.whenNew(URL.class).withParameterTypes(String.class)
.withArguments(Mockito.anyString()).thenReturn(url);
URL url1 = testClass.getUrl();
Assert.assertNotNull(url1);
}
}
I have used a URLHandler that allows me to load a URL from the classpath. So the following
new URL("resource:///foo").openStream()
would open a file named foo from within the class path. To do this, I use a common utility library and register a handler. To use this handler, you just need to call:
com.healthmarketscience.common.util.resource.Handler.init();
and the resource URL is now available.
Create a URL-object pointing to the test class itself.
final URL url =
new URL("file://" + getClass().getProtectionDomain().getCodeSource().getLocation().getPath());
I would look again at why you want to mock a final data object. Since by definition you aren't subclassing the object in your actual code, and it's not going to be the object under test, you shouldn't need to white-box test this code; just pass in whatever (real) URL objects are appropriate, and check the output.
Mock objects are useful when it's difficult to create a real object appropriate, or the real object's method are either time-consuming or depend on some stateful external resource (like a database). Neither of these apply in this case so I can't see why you can't just construct a real URL object representing the appropriate resource location.
JMockit does indeed allow you to mock a final JRE class like java.net.URL.
It seems the Attach API in jdkDir/lib/tools.jar available in implementations of JDK 1.6 other than Sun's does not work as well. I guess this stuff is still too new/advanced, or simply didn't get the necessary attention from the other JDK vendors (Apple, IBM with the J9 JDK, Oracle with the JRockit JDK).
So, if you run into problems by having tools.jar in the classpath, try using the "-javaagent:jmockit.jar" JVM argument. It tells the JVM to directly load the java agent at startup, without using the Attach API. That should work in the Apple JDK 1.5/1.6.
Does the URL class implement an interface? If so then you could instantiate it using inversion of control or a configurable factory, rather than by direct construction, this would allow you to inject/construct a test instance at test runtime rather than the final instance you currently have.
You can mock the constructor this way:
new MockUp<URL>() {
#Mock
public void $init(Invocation invocation, String string) {
}
};
Using PowerMockito for my case was the easiest solution. PowerMockito allows mocking static, final classes.

Categories