How to test OS-specific method with JUnit? - java

I would like to test the following method with JUnit:
private static boolean systemIsWindows() {
String os = System.getProperty("os.name").toLowerCase();
return os.startsWith("win");
}
Frankly, the only thing I've come up with is to basically copy to same logic to the test. This would, of course, protect against the method being inadvertently broken, but sounds somehow counter-intuitive.
What would be a better way to test this method?

In your Unit tests, you can change the value of the property:
System.setProperty("os.name", "Linux")
After that, you can then test/call your systemIsWindows() method to check that what it returns using asserts.
To make it easier to set a System property and to unset that property on completion of the test (thereby facilitating test isolation, self containment) you could use either of the following JUnit add-ons:
JUnit4: JUnit System Rules
JUnit5: JUnit Extensions
For example:
#Test
#SystemProperty(name = "os.name", value = "Windows")
public void aTest() {
assertThat(systemIsWindows(), is(true));
}
#Test
#SystemProperty(name = "os.name", value = "MacOs")
public void aTest() {
assertThat(systemIsWindows(), is(false));
}

A much better way in JUnit 5 is to use #EnabledOnOs https://junit.org/junit5/docs/5.2.0/api/org/junit/jupiter/api/condition/EnabledOnOs.html
So for example:
#Test
#EnabledOnOs({OS.WINDOWS})
public void aTest() {
assertThat(systemIsWindows(), is(false));
}

Related

Junit and Integration Tests best approach

I want to make some integration test to test my whole program (it's a standart command line Java application with program args)
Basically I have 3 tests : one to create a resource, one to update the resource and finally one to delete it.
I could do something like this :
#Test
public void create_resource() {
MainApp.main(new String[] {"create", "my_resource_name"});
}
#Test
public void update_resource() {
MainApp.main(new String[] {"update", "my_resource_name"});
}
#Test
public void delete_resource() {
MainApp.main(new String[] {"delete", "my_resource_name"});
}
It works... as long as the methods are executed in the correct order. I've heard that the good execution of a test should not depend of the order.
It's true that ordering tests is considered a smell. Having said that, there might be cases where it might make sense, especially for integration tests.
Your sample code is a little vague since there are no assertions there. But it seems to me you could probably combine the three operation into a single test method. If you can't do that then you can just run them in order. JUnit 5 supports it using the #Order annotation:
#TestMethodOrder(OrderAnnotation.class)
class OrderedTestsDemo {
#Test
#Order(1)
void nullValues() {
// perform assertions against null values
}
#Test
#Order(2)
void emptyValues() {
// perform assertions against empty values
}
#Test
#Order(3)
void validValues() {
// perform assertions against valid values
}
}

How to unit test a function that has a condition for the state of something?

I'm trying to write a unit test for a function that has a condition for wifi state. When the wifi state is disconnected, the function returns with false, but I want to simulate a scenario when the wifi state is connected. How do I go about it? Should I make a setter for the state variable? Isn't that a bad approach?
The function I want to test:
public boolean performSomething() {
if (WIFI_STATE != "connected") {
return false;
}else{
....
}
}
I want to test the else part of the function above, but as you may have guessed, the function executes the if condition, and returns false because WIFI_STATE is "disconnected"
Without seeing any of your code, make sure your class uses a WifiState constructor parameter or injection (or something similar). In your test you can then provide a mock for this object and set the state accordingly to your testing needs.
Two approaches that I can think of:
1: Define a sensor's state capturing class say WifiStatus, which your production code initializes automatically through a static initializer.
For testing, you can load a dummy WifiStatus class though a test initializer or change the value of WifiStatus through instrumentation.
2: Use WifiStatus as a interface and then mock it for dependency injection. This approach is more common.
public interface WifiStatus{
boolean isConnected();//
}
public class Performer{
WifiStatus wifiStatusProvider;
public Performer(WifiStatus stateProvider){
this.wifiStatusProvider = stateProvider;
}
public boolean performSomething() {
//if (WIFI_STATE != "connected") {
if (wifiStatusProvider.isConnected() != true) {
return false;
}else{
....
}
}
}
For test class, you use as follows:
public class PerformerTest{
#Test
public void verifyPerformSomething(){
WifiStatus dummyWifiStatus = mock(WifiStatus.class);
doReturn(true).when(dummyWifiStatus).isConnected();
new Performer(dummyWifiStatus).performSomething();
}
}
Assuming you are talking about "Local Unit Tests" and not "Instrumented Unit Tests", you can use Robolectric: http://robolectric.org
http://robolectric.org/javadoc/3.0/org/robolectric/shadows/ShadowWifiManager.html
https://github.com/robolectric/robolectric/blob/master/robolectric/src/test/java/org/robolectric/shadows/ShadowWifiManagerTest.java
Local Unit Tests:
https://developer.android.com/training/testing/unit-testing/instrumented-unit-tests.html
Instrumented Unit Tests:
https://developer.android.com/training/testing/unit-testing/instrumented-unit-tests.html
Well, for testing, you must be sure for your input how your output looks like because you need to compare them. Make the boolean value of wifi state is injected from outside, so you can mock it how you like. For example:
public boolean method(boolean wifiState){
return !wifiState;
}
So now you can be sure that if your parameter is false you will got true and vice versa so you can mock that param and make your tests.
Chiming in with a code-based answer based on john16384's answer. You mention that the state is set with other functions within the same class, assuming those methods are public I propose something like this (assuming WifiChecker is your class):
private WifiChecker wifiChecker;
#Before public void setUp() {
wifiChecker = new WifiChecker();
}
#Test public void testWifiConnected() {
wifiChecker.setConnected()
assertTrue(wifiChecker.performSomething());
}
#Test public void testWifiDisconnected() {
wifiChecker.setDisconnected()
assertFalse(wifiChecker.performSomething());
}

Execute order for test suite in junit

I am having a test suite which is having the following structure
TestClass1
- testmethod1()
- testmethod2()
- testmethod3()
- testmethod4()
TestClass2
- testmethod11()
- testmethod22()
- testmethod33()
- testmethod44()
In the above structure i want to execute the testmethod4() as the final one. ie) executed at last.
There is a annotation #FixMethodOrder which executes a method in order not the testclass. Is there any mechanism to maintain order in test class and testmethod together. With the #FixMethodOrder i can execute the method by renaming the name of the test method but i can't instruct junit to execute the test class as the final one(last one).
Though quoting #Andy again -
You shouldn't care about test ordering. If it's important, you've got
interdependencies between tests, so you're testing behaviour +
interdependencies, not simply behaviour. Your tests should work
identically when executed in any order.
But if the need be to do so, you can try out Suite
#RunWith(Suite.class)
#Suite.SuiteClasses({
TestClass2.class,
TestClass1.class
})
public class JunitSuiteTest {
}
where you can either specify
#FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class TestClass1 {
#AfterClass
public void testMethod4() {
and then take care to name your method testMethod4 as such to be executed at the end OR you can also use #AfterClass which could soon be replaced by #AfterAll in Junit5.
Do take a look at Controlling the Order of the JUnit test by Alan Harder
#shiriam as #Andy Turner already pointed out, the order of your tests shouldn't come in question when running the tests.
If you have a routine that you want executed before doing any tests, you could use a static block of code in one of the classes.
Think of something like this:
class TestBootstrap {
// singleton instance
private static final instance;
private boolean initialized;
private TestBootstrap(){
this.initialized = false;
}
public static TestBootstrap getInstance(){
if (instance == null){
instance = new TestBootstrap()
}
}
public void init(){
// make the method idempotent
if (!initialzed){
// do init stuff
initialized = true;
}
}
public boolean isInitialized(){
return initialized;
}
}
Then in your tests use something like this:
class TestClass1{
#BeforeClass
public void setup(){
TestBootstrap.getInstance().init();
}
#Test
public void testmethod1(){
// assertions
}
// ....
}
class TestClass2{
#BeforeClass
public void setup(){
TestBootstrap.getInstance().init();
}
#Test
public void testmethod11(){
// assertions
}
// ...
}
By using the singleton instance for doing the setup for the tests you ensure that you perform the initialization of your test environment only once, independently of the order in which the test classes are executed.

JUnit4 - Test if method does nothing

How can I test if a method does nothing. For example I have a static method that throws an exception if the given string-argument is null or empty (it's meant for argument-validation). Right now my tests look like this:
#Test
public void notNullOrEmpty_doesNothingIfValueIsNotNullOrEmpty() {
Require.notNullOrEmpty(Generate.randomString());
assertTrue(true); // <- this looks very ugly
}
#Test(expected = IllegalArgumentException.class)
public void notNullOrEmpty_throwsExceptionIfValueIsNull() {
Require.notNullOrEmpty(null);
}
#Test(expected = IllegalArgumentException.class)
public void notNullOrEmpty_throwsExceptionIfValueIsEmpty() {
Require.notNullOrEmpty("");
}
How can I make the first test to pass without calling assertTrue(true), there is a Assert.fail() is there something like an Assert.pass()?
EDIT:
Added missing (expected = IllegalArgumentException.class) to 3rd test
You have just to remove the assert in the first method.
#Test
public void notNullOrEmpty_doesNothingIfValueIsNotNullOrEmpty() {
Require.notNullOrEmpty(Generate.randomString());
// Test has passed
}
If the test method runs completely then it means it pass with success. Look at Eclipse junit output:
Update: as an additional comment, if you use Mockito framework you can leverage verify method to verify that a method was called X times. For instance, I used something like this:
verify(cmAlertDao, times(5)).save(any(CMAlert.class));
In your case, since you are testing static methods, then you might find useful using PowerMock which allows you to verify static methods (since Mockito doesn't). And you can use verifyStatic(...).
You should add #Test(expected = YourException.class) annotation.
Try to add to the first test:
#Test
public void notNullOrEmpty_doesNothingIfValueIsNotNullOrEmpty() {
String str = Generate.randomString();
Require.notNullOrEmpty(str);
assertNotNull(str);
}
and probably to you have better to rename it to notNullOrEmpty_doesNothingIfValueIsNotNullOrNotEmpty because you are testing it for not empty value.
A unit test must assert which is expected in the behavior of the method.
If in your specification, when your call notNullOrEmpty()no exception must be thrown when the data is valid and an exception must be thrown when the data is not valid so in your unit test you must do no assertion when the data is valid since if it doesn't success, a exception will be thrown and the test will so be in failure.
#Test
public void notNullOrEmpty_doesNothingIfValueIsNotNullOrEmpty() {
Require.notNullOrEmpty(Generate.randomString());
}

Passing JUnit data between tests

I just discovered when creating some CRUD tests that you can't set data in one test and have it read in another test (data is set back to its initialization between each test).
All I'm trying to do is (C)reate an object with one test, and (R)ead it with the next. Does JUnit have a way to do this, or is it ideologically coded such that tests are not allowed to depend on each other?
Well, for unit tests your aim should be to test the smallest isolated piece of code, usually method by method.
So testCreate() is a test case and testRead() is another. However, there is nothing that stops you from creating a testCreateAndRead() to test the two functions together. But then if the test fails, which code unit does the test fail at? You don't know. Those kind of tests are more like integration test, which should be treated differently.
If you really want to do it, you can create a static class variable to store the object created by testCreate(), then use it in testRead().
As I have no idea what version of Junit you talking about, I just pick up the ancient one Junit 3.8:
Utterly ugly but works:
public class Test extends TestCase{
static String stuff;
public void testCreate(){
stuff = "abc";
}
public void testRead(){
assertEquals(stuff, "abc");
}
}
JUnit promotes independent tests. One option would be to put the two logical tests into one #Test method.
TestNG was partly created to allow these kinds of dependencies among tests. It enforces local declarations of test dependencies -- it runs tests in a valid order, and does not run tests that depend on a failed test. See http://testng.org/doc/documentation-main.html#dependent-methods for examples.
JUnit is independent test. But, If you have no ways, you can use "static" instance to store it.
static String storage;
#Test
public void method1() {
storage = "Hello"
}
#Test
public void method2() {
Assert.assertThat(something, is(storage));
}
How much processing time do these tests take? If not a lot, then why sweat it. Sure you will create some object unnecessarily, but how much does this cost you?
#Test
void testCreateObject() {
Object obj = unit.createObject();
}
#Test
void testReadObject() {
Object obj = null;
try {
obj = unit.createObject(); // this duplicates tests aleady done
} catch (Exception cause) {
assumeNoException(cause);
}
unit.readObject(obj);
}
in this basic example, the variable is changed in the test A, and can be used in the test B
public class BasicTest extends ActivityInstrumentationTestCase2 {
public BasicTest() throws ClassNotFoundException {
super(TARGET_PACKAGE_ID, launcherActivityClass);
}
public static class MyClass {
public static String myvar = null;
public void set(String s) {
myvar = s;
}
public String get() {
return myvar;
}
}
private MyClass sharedVar;
#Override
protected void setUp() throws Exception {
sharedVar = new MyClass();
}
public void test_A() {
Log.d(S,"run A");
sharedVar.set("blah");
}
public void test_B() {
Log.d(S,"run B");
Log.i(S,"sharedVar is: " + sharedVar.get());
}
}
output result is:
run A
run B
sharedVar is: blah

Categories