I'm just getting into testing of code. I have done unit tests before but haven't really isolated them. So they were more like integration test (indirectly). I want to give Mockito a try and I have added it to my Intellij IDE.
But I have no idea of how to actually implement mocking at all. There are examples on their website but I just can't wrap my head around the concept of mocking. I know that one uses mocking to isolate the unit testing to ensure that the errors are in the unit itself and not in a dependency.
I wrote the following:
#Test
public void testChangeMemberReturnsTrue() throws Exception {
Member tempMem = new Member();
tempMem.setMemberFirstName("Swagrid");
tempMem.setMemberLastName("McLovin");
tempMem.setMemberID("SM666");
SQLDUMMY.saveMember(tempMem); //Save member to dummy DB.
Member checkMem = new Member();
ArrayList<Member> memArr = SQLDUMMY.getAllMembers();
for (Member m : memArr) { // Look through all saved members
if (m.equals(tempMem)) { // If match, save to checkMem
checkMem = m;
}
}
assertTrue(tempMem.equals(checkMem)); // Make sure they are really equal.
String newfirstname = "Darius";
String newlastname = "DunkMaster";
assertTrue(memhandling.changeMember(tempMem, newfirstname, newlastname));
}
And here is the actual method:
public boolean changeMember(Member mem, String n1, String n2) {
try {
ArrayList<Member> memArr = SQLDUMMY.getAllMembers();
for (Member m : memArr) {
if (m.equals(mem)) {
m.setMemberFirstName(n1);
m.setMemberLastName(n2);
m.setMemberID(ensureUniqueID(m, m.getMemberID())); //Just a method call to another method in the same class to ensure ID uniqueness.
return true;
}
else {
return false;
}
}
}
catch (Exception e) {
System.out.println("Error4.");
}
return false;
}
I'd like to mock the SQLDUMMY (Which I created just to see if my tests would pass at all, which they do.) The SQLDUMMY class looks like this:
public class SQLDUMMY {
private static ArrayList<Member> memberList = new ArrayList<>();
private static ArrayList<Ship> shipList = new ArrayList<>();
public static ArrayList<Member> getAllMembers() {
return memberList;
}
public static void saveMember(Member m) {
memberList.add(m);
}
public static void deleteMember(Member memIn) {
memberList.remove(memIn);
}
public static void saveShip(Ship newShip) {
shipList.add(newShip);
}
public static ArrayList<Ship> getAllShips() {
return shipList;
}
public static void deleteShip(Ship s) {
shipList.remove(s);
}
}
It basically just consists of getters and add/remove for the ArrayLists that act as a contemporary DB storage.
Summary: How can I mock the SQLDUMMY class (DAO), so it is no longer a dependency for the Unit tests?
You need to read on how Mockito works.
The basic idea is that it extends you class and and overrides all methods and allows you to return what ever you want it too.
Syntax is :
SQLDummy sqlDummy = Mockito.mock(SQLDummy.class);
Mockito.when(sqlDummy.getAllShips()).thenReturn(new ArrayList< Ship >())
Related
Forgive the elementary question, I am learning Java still so need some advice on best practice here. I have a valid scenario where I wish to share the same object between two distinct Test classes using JUnit or TestNG. I understand that tests/test classes should not usually share state but this is a long-running journey.
I understand the JVM executes for both frameworks in this order:
#BeforeClass
Construcor call
#Before
#Test
Given I have an Person class with one field name and one getter & setter for same and I instantiate an instance of it in one Test Class:
public class FirstPersonTest {
private Person firstPerson;
#BeforeClass
private void setup() {
firstPerson = new Person("Dave");
}
#Test
public void testName() {
assertEquals("Dave", firstPerson.getName());
}
}
And a second Test class:
public class SecondPersonTest {
private Person firstPerson;
private static String name;
#BeforeClass
private void setup(){
name = firstPerson.getName(); //null pointer, firstPerson reference no longer exists from FirstPersonTest
}
#Test
public void testName(){
assertEquals("Dave", name);
}
}
What is the optimal way of accessing the firstPerson object in the second class? I don't want to instantiate it a second time because I wish to share state for a journey test.
I want to be able to pass firstPerson instance in the constructor or an annotated setup method, but don't wish to instantiate the SecondPersonTest within the body of FirstPersonTest
You can use a singleton class for this purpose.
public class LocalStorage {
private static volatile LocalStorage instance;
private Map<String, Object> data = new HashMap<>();
private LocalStorage() {
}
public static LocalStorage getInstance() {
if (instance == null) {
synchronized (LocalStorage.class) {
if (instance == null) {
instance = new LocalStorage();
}
}
}
return instance;
}
public static void addData(String key, Object value) {
getInstance().data.put(key, value);
}
public static Object getData(String key) {
return getInstance().data.get(key);
}
public static <T> T getData(String key, Class<T> clazz) {
return clazz.cast(getInstance().data.get(key));
}
}
You can store the whole Person object or only the name field of the Person object.
To store:
Person firstPerson = new Person("Dave");
LocalStorage.addData("Dave", firstPerson);
To get it back:
Person firstPerson = LocalStorage.getData("Dave", Person.class);
I have class that has 3 methods: insert, update and delete from the db.
In order to test it in the insert test method I need to use the insert method and after I insert i need to delete what I inserted, but in order to delete I should use the delete method that I also want to test so it didn't make sense to me that I need to use them and also test them.
I hope you understand my problem. Thanks in advance!
You must decide what you want to test. That was you describe, it is an integration test. By a “real” unitTest, you test only your method, and not the System method and not the database.
If you want a unitTest, you have several options. For Example, you work with interfaces and catch your statement before it comes to the database.
Edit 1 - one possibility to implement unit test with interfaces:
You need one interface that implements the method these go to the backend system:
public interface IDatabase{
public returnValue insert(yourParam);
public int update(yourParam);
}
Then you implement your method with the real functions in a class:
public class Database implements IDatabase {
#Override
public returnValue insert(yourParam) {
// do something
return null;
}
#Override
public int update(yourParam){
// do something
return 0;
}
}
This class you call in the main class:
/**
* The real class to do what you want to do.
*/
public class RealClass {
private IDatabase dbInstance = null;
private IDatabase getDbInstance() {
if (dbInstance == null) {
dbInstance = new Database();
}
return dbInstance;
}
protected void setDbInstance(IDatabase dataBase) {
dbInstance = dataBase;
}
public static void main(String[] args) {
getDbInstance().insert(yourParam);
}
}
For the unit test you implement the interface again:
public class UnitTest implements IDatabase {
#Override
public returnValue insert(yourParam) {
// Here can you test your statement and manipulate the return value
return null;
}
#Override
public int update(yourParam){
if (yourParam.containsValue(value1)) {
assertEquals("yourStatement", yourParam);
return 1;
}else if (yourParam.containsValue(value2)) {
assertEquals("yourStatement2", yourParam);
return 5;
}else{
assertTrue(false,"unknown Statement")
}
}
#Test
public void yourTest(){
RealClass.setDbInstance(this);
//Test something
}
}
This is time-consuming to implement, but with this, you are independent from the backend system and you can call the unittest every time without a database.
By default, the order of test methods is not warrantied in JUnit. Nevertheless, as of JUnit 4.11, you can order by the test name, as follows:
import org.junit.FixMethodOrder;
import org.junit.Test;
import org.junit.runners.MethodSorters;
#FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class Test1 {
#Test
public void aInsert() {
System.out.println("first INSERT");
}
#Test
public void bUpdate() throws Exception {
System.out.println("second UPDATE");
}
#Test
public void cDelete() throws Exception {
System.out.println("third DELETE");
}
}
When creating a test below
#Test
public void myTest() {
MyRepo myRepo = Mockito.mock(MyRepo.class);
when(myRepo.getMyItemList()).thenReturn(createMyItemList(3));
// More Test verification
}
private List<MyItem> createMyItemList(int count) {
List<MyItem> myItemList = new ArrayList<>();
while (count > 0) {
myItemList.add(createMyItem());
count--;
}
return myItemList;
}
private MyItem createMyItem() {
MyItemDetail myItemDetail = new MyItemDetail();
ItemDetailGen itemDetailGen = Mockito.mock(ItemDetailGen.class);
when(itemDetailGen.getItem()).thenReturn(myItemDetail);
return new MyItem(itemDetailGen);
}
I got error on the line of when(itemDetailGen... when running it
org.mockito.exceptions.misusing.UnfinishedStubbingException:
Unfinished stubbing detected here:
-> at ...
E.g. thenReturn() may be missing.
Examples of correct stubbing:
when(mock.isOk()).thenReturn(true);
when(mock.isOk()).thenThrow(exception);
doThrow(exception).when(mock).someVoidMethod();
Hints:
1. missing thenReturn()
2. you are trying to stub a final method, you naughty developer!
If I debug into it, the crash happens on when(myRepo.getMyItemList... instead.
Why is this problem?
It seems like a return of a mock function (i.e. createMyItemList), shouldn't contain another mock within. My temporary fix is remove the private function mock, by creating a new constructor for MyItem to directly accept MyItemDetail object as below, which is not ideal, since the actual code doesn't use that.
private MyItem createMyItem() {
MyItemDetail myItemDetail = new MyItemDetail();
return new MyItem(myItemDetail);
}
UPDATED
Just to make it clearer, I'm showing all the class (simplified) content.
class MyRepo {
List<MyItem> myItemsList;
List<MyItem> getMyItemList() {
return myItemsList;
}
void addMyItemList(List<MyItem> myItemsList) {
this.myItemsList = myItemsList;
}
}
class MyItem {
private MyItemDetail myItemDetail;
public MyItem(ItemDetailGen itemDetailGen) {
this.myItemDetail = itemDetailGen.getItem();
}
public MyItem(MyItemDetail myItemDetail) {
this.myItemDetail = myItemDetail;
}
}
class MyItemDetail {
}
class ItemDetailGen {
MyItemDetail getItem() {
return new MyItemDetail();
}
}
Combine the class code and the test code, the entire test could be run to demonstrate the issue clearly.
I have a following code
public class Component extend Framework {
private Integer someInt;
private String someString;
public Integer getSomeInt() {
return someInt;
}
public String getSomeString() {
return someString;
}
public void activate() {
Integer tempInt = (Integer)getProperties("key"); // From Framework
if (tempInt == null) {
tempInt = (Integer)getRequest().getProperties("key"); // From Framework
}
if(tempInt == null)
tempInt = (Integer)getBind().getProperties("key"); // From Frameowrk
someString = makeServiceCall("http://.....?key=tempInt");
}
}
Basically activate() method is called by the framework in order to access internal state of the framework to construct Component object. activate() is sort of like a setter for the Component object.
If I were to unit test the code above, what would be the best way to do it without having to have framework running?
One way would be to mock out Component class and stub the super.getProperties... calls, however if we mock the class in question, what is the point of testing to begin with?
I will show how to test one edge case
void testServiceCallWithNoKeyPropertyFound() {
Component componentUnderTest = new Component() {
Integer getProperties(String key) {
return null; // property should not be found
}
Request getRequest() {
return new Request(...); //this request should not contain a property named "key",
}
Bind getBind() {
return new Bind(...); //this bind should not contain a property named "key"
}
String makeServiceCall(String url) {
if (url.endsWith("null")) {
return success;
}
throw new AssertionError("expected url ending with null, but was " + url);
}
};
componentUnderTest.activate();
assertThat(componentUnderTest.getSomeString(), equalTo("success"));
}
Using Mockito (spys) can make this example much more concise. But this would hide the principles how to design the test.
There are some more edge cases:
void testServiceCallWithPropertyFoundInComponent() ...
void testServiceCallWithPropertyFoundInRequest() ...
void testServiceCallWithPropertyFoundInBind() ...
Use Mockito.
Spy the Component class and mock the methods getRequest() and getBind().
Finally, call the activate() method directly from your unit test.
I think it could be a smell of bad design. Maybe you should consider composition instead of inheritance? It would be more testing friendly and more objective. Why Component is inheriting from Framework class?
public class Component {
private int someInt;
private String someString;
private Framework framework;
public Component(Framework framework) {
this.framework = framework
}
public int getSomeInt() {
return someInt;
}
public String getSomeString() {
return someString;
}
public void activate() {
int tempInt = framework.getProperties("key"); // From Framework
if (tempInt == null) {
tempInt = framework.getRequest().getProperties("key"); // From Framework
}
if(tempInt == null)
tempInt = framework.getBind().getProperties("key"); // From Frameowrk
someString = makeServiceCall("http://.....?key=tempInt");
}
}
I have UI automation tests. Tests involve three entities -
Data object class - data to be filled in forms. Herein each form on a page could be represented by a different data object.
Helper class - which fills in data in a form on page
Test class - which uses data object and helper class to perform test.
Following is the cut down version of test -
public class ParallelDataObject {
HelperClass helperClass = new HelperClass();
Data data;
#BeforeMethod
public void setTestData() {
data = new Data();
helperClass.setData(data);
}
#Test
public void passM1() {
helperClass.verifyFlag();
}
#Test
public void failM2() {
data.setFlag(false);
helperClass.setData(data);
helperClass.verifyFlag();
}
#Test
public void passM3() {
helperClass.verifyFlag();
}
#Test
public void failM4() {
data.setFlag(false);
helperClass.setData(data);
helperClass.verifyFlag();
}
}
class HelperClass {
Data data;
public void setData(Data data) {
synchronized (data) {
this.data = data;
}
}
public void verifyFlag() {
synchronized (data) {
assert data.getFlag();
}
}
}
class Data {
private boolean flag;
public Data() {
flag = true;
}
public Data setFlag(boolean flag) {
synchronized (this) {
this.flag = flag;
return this;
}
}
public boolean getFlag() {
synchronized (this) {
return flag;
}
}
When executing methods in parallel I encountered weird results as data is not thread safe. Then I incorporated synchronize blocks but yet I encounter weird results.
I am sure I have messed up how synchronization should be used here in. Any insight?
I did one more exercise. I set up another Test class exactly same as first test class. I removed all synchronization from helper and data class. When I run classes in parallel (instead of methods). Test results are as expected. Why don't I run in to concurrency when I execute classes in parallel, even though they user same helper class and data object?
HelperClass and Data are thread-safe.
The problem is that some of your test methods perform several operations. And sequence of the operations in test method is not atomic as long as it not synchronized.
For example during failM4 execution the state of helperClass might be modified by other thread.
I'd recommend you to not use shared state between test methods because synchronization will nullify the advantages of concurrent tests execution.
Consider using ThreadLocal. This way each thread has its own copy of HelperClass. Note that synchronizing separate methods won't give you anything - changes made in one test (in one thread) are visible by other tests
class ParallelDataObject {
private final ThreadLocal<HelperClass> helperClassThreadLocal = new ThreadLocal<HelperClass>() {
#Override
protected HelperClass initialValue() {
return new HelperClass(new Data());
}
};
private HelperClass helperClass() {
return helperClassThreadLocal.get();
}
#Test
public void passM1() {
helperClass().verifyFlag();
}
#Test
public void failM2() {
helperClass().getData().setFlag(false);
helperClass().verifyFlag();
}
}
class HelperClass {
private final Data data;
public HelperClass(Data data) {
this.data = data;
}
public Data getData() {
return data;
}
public void verifyFlag() {
assert data.getFlag();
}
}
class Data {
private boolean flag = true;
public Data setFlag(boolean flag) {
this.flag = flag;
return this;
}
public boolean getFlag() {
return flag;
}
}
Other improvements:
passM3 and failM4 were superfluous
since HelperClass requires an instance of Data to work, it should declare it using constructor dependency
when using:
synchronized(this)
wrapping whole method body, consider using synchronized keyword in method declaration instead (more readable).
synchronization is no longer needed with ThreadLocals
Test statelessness
#gpeche makes a good suggestion that tests should be independent. Unfortunately (why, oh why!?) JUnit reuses the same test case class instance (ParallelDataObject in this case) for all test methods execution. This means that assigning any stateful objects to test case class fields is dangerous and must be avoided.
In this particular case the OP would have to create a new instance of HelperClass in each test method (which, in fact, isn't such a bad idea):
class ParallelDataObject {
#Test
public void passM1() {
final HelperClass helperClass = new HelperClass(new Data());
helperClass.verifyFlag();
}
#Test
public void failM2() {
final Data data = new Data();
data.setFlag(false);
final HelperClass helperClass = new HelperClass(data);
helperClass.verifyFlag();
}
}