How to write unit test for a Button using white box? - java

I have a list of rows in the table and a moveUpButton, it will move selected rows to one step up. It works fine but I need to write unit test using white box for this method.
Here is my code:
public void registerMoveUpBut(final Button moveUpBut){
this.moveUpBut = moveUpBut;
moveUpBut.addActionListener(new ActionListener){
public void actionPerformed(ActionEvent event){
Transferevent obj = transModel.getElementAt(TransTable.getSelectedRow);
TransferObj transferObj = new TransferObj(obj);
transferObj.setEventType(TransferTypeEnum.UP);
transferObj.setEventNum(obj.getEventNum()-1)
}
}
}
Unit test I have so far is
#Test
public void testMoveUpBut(){
Controller Con = mock(Controller.class)
JButton moveUpBut = Whitebox.getInternalState(Con, "moveUpBut");
//here i want to use something like addListener so that it will pass through my
//method and use ArgumentCaptor to verify whether it's population the data or
//not. Can you pls help with that, Thank you!
moveUpBut.addActionerListener() //something like this
ArgumentCaptor<Controller>argument = ArgumentCaptor.forClass(Controller.class);
verify().doSomething(argumentCapture));
}

Related

Espresso: What are the advantages/disadvantages of having multiple tests vs. one user journey?

As an example, I have an app with a MainActivity that has a button and a NextActivity that has a RecyclerView populated with the integers in a vertical list. I could write the following separate Espresso tests:
Test 1:
public class MainScreenTest {
#Rule
public IntentsTestRule<MainActivity> mainActivityRule =
new IntentsTestRule<>(MainActivity.class);
#Test
public void shouldOpenNextActivityOnClick() {
onView(withId(R.id.btn)).check(matches(withText("foo")));
onView(withId(R.id.btn))
.perform(click());
intended(hasComponent("com.example.androidplayground.NextActivity"));
}
}
Test 2:
public class NextScreenTest {
#Rule
public ActivityTestRule<NextActivity> nextActivityRule =
new ActivityTestRule<>(NextActivity.class);
#Test
public void shouldScrollToItem() throws Exception {
int position = 15;
onView(withId(R.id.rv))
.perform(RecyclerViewActions.scrollToPosition(position));
onView(withText(position)).check(matches(isDisplayed()));
}
}
Alternatively, I could write one test that covers both:
public class UserJourneyTest {
#Rule
public ActivityTestRule<MainActivity> mainActivityRule =
new ActivityTestRule<MainActivity>(MainActivity.class);
#Test
public void userJourney() {
onView(withId(R.id.btn)).check(matches(withText("foo")));
onView(withId(R.id.btn))
.perform(click());
int position = 15;
onView(withId(R.id.rv))
.perform(RecyclerViewActions.scrollToPosition(position));
onView(withText(position)).check(matches(isDisplayed()));
}
}
Is one way better than the other? Will I gain a significant increase in performance by having one user journey instead of multiple separate tests?
My opinion is that if you're navigating from MainActivity to NextActivity by clicking a button, you wouldn't want to write a test which launches directly the NextActivity. For sure, espresso allows this, but if from MainActivity there are some data passed to NextActivity, you won't have them if your test launches NextActivity directly.
I'd say that first of all by writing a UI automation test you want to simulate a user's behaviour. So that I would go for the third option you've posted above, UserJourneyTest.class
In your case it's not a matter of performance, it's a matter of testing it right.

Java - Linking a JTextField variable with another class variable

What I want to achieve is very simple.
I have 2 classes. "SpeedingTicket" & "SpeedingTicket GUI".
Inside my GUI I have 1 textbox name txtSpeedLimit & a button.
Inside my SpeedingTicket class I have a variable "int speedingTicket".
Inside my SpeedingTicket class I also have a get & set method for "speedingTicket".
I know how to get and set text using JTextFields, but I want to be able to:
receive input from the "txtSpeedLimit", and store that value into the "txtSpeedLimit" instance variable in the "SpeedTicket" class. I can then check for validation etc when I come to adding the vehicle speed.
Maybe this isn't the most efficient way of dealing with this program. Maybe I should scrap the instance variables in SpeedingTicket, and deal with it all in the GUI.
Any advice would be hugely appreciated.
Basically what I'm trying to do is this:
class confirmHandler implements ActionListener{
public void actionPerformed(ActionEvent e){
String val = txtSpeedLimit.getText();
int realNum = speed.getSpeedLimit() = txtSpeedLimit; < but obviously that doesn't work, but I want the textbox link to the variable.
EDIT: If we take away the GUI, all I want my program to do is the following:
Speed Limit: 50 < enterd via textfield
Speed: 60 < entered via textfield
if the speed is blah blah (ive already coded this).. then output a result to one of my labels.
I achieved this without making a GUI and making it only console based, but instead of the user typing it via the console, I want it to be typed via textfields.
THe values that are entered into the textfields should be stored in the two variables (speed and speedlimit) that are in the SpeedingTicket class.
You can update a value in:
public class SpeedingTicket {
int speedingTicket;
public SpeedingTicket() {
speedingTicket = 500;
}
public int getSpeedingTicket() {
return speedingTicket;
}
}
by:
public class SpeedingTicketGUI extends JPanel{
SpeedingTicket st;
SpeedingTicketGUI() {
st = new SpeedingTicket();
setLayout(new FlowLayout(FlowLayout.LEFT));
JTextField txtField = new JTextField(10);
txtField.setText(""+st.getSpeedingTicket());
add(txtField);
JButton btn = new JButton("Update");
btn.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
setSpeedingTicket(txtField.getText());
}
});
add(btn);
}
private void setSpeedingTicket(String text) {
try {
int speedTicket = Integer.parseInt(text);
st.setSpeedingTicket(speedTicket);
System.out.println("Speeding ticket set to " +st.getSpeedingTicket());
} catch (NumberFormatException ex) {
System.out.println("Invalid value " +text);
ex.printStackTrace();
}
}
public static void main(String[] args){
JFrame frame = new JFrame("Speeding Ticket");
frame.setSize(400,100);
frame.add(new SpeedingTicketGUI());
frame.setVisible(true);
}
}
You don't need to store values in JText or any GUI componenets...
Use global static variables. For example:
public static int speed_limit;
You can access this variable from ANY method,class, etc.
There are multiple ways to do it.
You can detect textfield changes by using a DocumentListener or if you want (not recommended) by a KeyListener.
The Listener could be implemented directly by your gui class or by your other class. If you want more abstraction you could implement the DocumentListener by your gui class and create a method
public void addSpeedChangeListener(SpeedChangeListener scl) {
this.speedChangeListeners.add(scl);
}
Your SpeedChangeListener could be very simple:
public interface SpeedChangeListener {
public void speedChanged(int value);
}
Then your second class implements the SpeedChangeListener and calls addSpeedChangeListener(this) on your gui class. Inside the gui class, your document listener calls speedChanged(val) for every listener registered.
EDIT
You can also use the Button and call the speedChanged on every listener inside the actionPerformed method of the ActionListener.
I think it would be easier to use a JOptionDialog which pop ups when the button is clicked. That way you can easily get input and also validate the input straight away.

How to find out whether Method has called for given instance. Like "Object obj" check whether obj called "equals" method or not

I want to find out whether method for some object is being called for that instance or not.
Is it possible in java ?
Like ...
class Button {
public void focus(){}
public void setName(){}
}
class MyTest {
public static void main(String[] args){
Button button = new Button();
button.focus();
// I want to find out on button instance whether focus() or setName() is called or not.
whetherMethodCalled(button);
// OR
whetherMethodCalled(button, 'focus');
whetherMethodCalled(button, 'setName');
}
}
EDIT : Forgot to add Button class is third party class which I cannot modify... Also I want to check in my code whether method has called for given object instance or not on basis of that I have to write some code.
In order to reduce extra work, perhaps profiling your application with JConsole or another tool is good enough to show if certain methods have run. Another option is using a code coverage tool like EMMA which detects dead code. There is a list of open-source profilers for Java at http://java-source.net/open-source/profilers and EMMA is at http://emma.sourceforge.net/.
With some extra work AspectJ could be use to intercept method calls without changing existing code. For example, the following would intercept calls to Button.focus()
#Aspect
public class InterceptButtonMethods {
#Before("execution(* Button.focus())")
public void beforeInvoke() {
System.out.println("Button.focus invoked");
incrementFocusCount();
}
}
If more extra work is ok, there is a way to wrap all calls to the Button's focus() and setName() methods so that they update separate counters in addition to their normal functions. This can be done by extending Button in YourButton class which is identical to Button except for a couple of int counters with getters, setters and increment methods; and countingFocus() and countingSetName() methods which update their counters and call focus() and setName() respectively, such as in outline:
Class YourButton extends Button {
int focusCount;
int setNameCount
int getFocusCount() {return this.focusCount;}
void setFocusCount(int counter) {this.focusCount = counter} // optional to reset counter
void incrementFocusCount() {this.focusCount = getFocusCount() + 1;)
...
void countingFocus() {
incrementFocusCount();
focus()
}
...
}
If it is required in many places and involves complex things, I recommend to use Mockito to test your code. Using that you can verify if the method was invoked (also how many times if invoked)
You can mock the button and verify in your MyTest how many times the method must be called. Using Mockito you can mock and stub your methods(Stubbing voids requires different approach from when(Object) because the compiler does not like void methods inside brackets) and then verify it using verify statement.
verify(mockButton, times(1)).focus();
verify(mockButton, times(1)).setName();
You can write a wrapper class over the 3rd party Button class through which all calls to Button class will be made.
This wrapper class can keep track of whether each method has been called or not
class ButtonCaller {
private Button button = null;
private boolean focusCalled;
private boolean setNameCalled;
public ButtonCaller() {
button = new Button();
focusCalled = false;
setNameCalled = false;
}
public void focus() {
button.focus();
focusCalled = true;
}
public void setName() {
button.setName();
setNameCalled = true;
}
public void whetherMethodCalled(ButtonMethod method) {
switch (method) {
case FOCUS:
return focusCalled;
case SET_NAME:
return setNameCalled;
}
throw new RuntimeException("Unknown ButtonMethod !!!");
}
public static Enum ButtonMethod {
FOCUS,
SET_NAME;
}
}

Mockito stubbing void methods

I am currently writing unit tests for my selenium project and I am using Mockito to mock up my webelements and drivers.
The problem I am having is that I have a function that is used to change the radio option in a list of radio buttons but I am having a problem with this. the code looks like this:
#Test
public void testChangeRadioState(){
WebElement mockElement = mock(WebElement.class);
List<WebElement> mockElementList = new ArrayList<>();
WebElement selectedMockElement = mock(WebElement.class);
/*The when statements*/
when(selectedMockElement.isSelected()).thenReturn(true);
doReturn(when(mockElement.isSelected()).thenReturn(true)).when(mockElement).click();
doReturn(when(selectedMockElement.isSelected()).thenReturn(false)).when(mockElement).click();
/*Add a selected and a none selected element to the list*/
mockElementList.add(mockElement);
mockElementList.add(selectedMockElement);
/*The method that is beeing tested*/
elementSetter.changeRadioState(mockElementList);
Assert.assertTrue("The radio state was not selected",mockElement.isSelected());
}
What I am trying to do int he doReturn part is to tell the element "mockElement" that when it recieves a click it should allways return true on a isSelected() call. but since Click() is a void function it won't let me do that. Anybody know a way around this?
Ok, it is separate topic - what you are testing and would I mock things so deep.
I would just rewrite test like this:
#Test
public void testChangeRadioState() {
WebElement mockElement = mock(WebElement.class);
WebElement selectedMockElement = mock(WebElement.class);
List<WebElement> mockElementList = new ArrayList<>();
/*The when statements*/
when(selectedMockElement.isSelected()).thenReturn(true);
// By default mockito will return false but maybe I want to highlight
// that this is important
when(mockElement.isSelected()).thenReturn(false);
/*Add a selected and a none selected element to the list*/
mockElementList.add(mockElement);
mockElementList.add(selectedMockElement);
/*The method that is beeing tested*/
elementSetter.changeRadioState(mockElementList);
verify(selectedMockElement).click();
// according to test method name I would add
// one more verification that something was dis-selected
}
Another variant with state which I think has unnecessary mocks:
boolean selected;
#Test
public void testChangeRadioState() {
selected = false;
WebElement mockElement = mock(WebElement.class);
WebElement selectedMockElement = mock(WebElement.class);
List<WebElement> mockElementList = new ArrayList<>();
/*The when statements*/
when(selectedMockElement.isSelected()).thenReturn(true);
doAnswer(new Answer<Object>() {
public Object answer(InvocationOnMock invocation) {
selected = true;
return null;
}
}).when(mockElement).click();
/*Add a selected and a none selected element to the list*/
mockElementList.add(mockElement);
mockElementList.add(selectedMockElement);
/*The method that is beeing tested*/
elementSetter.changeRadioState(mockElementList);
Assert.assertTrue("The radio state was not selected", selected);
// according to test method name I would add
// one more verification that something was dis-selected
}
But again there is misleading in names. For example I would expect that there are elements which don't become selected when they clicked. Question again about what you are testing

How do I pass the values from one class to another?

I have this gui pop up panel and it got things to filled up like packets number, distance etc. Once users fill in the information, he will click ok, the gui will close and my other gui class which has calculation method should receives all data that are filled in earlier gui. How do I store that data? I know I can store in temp file but I don't want to do that. I hope you can enlighten me.
import java.awt.*;
import java.applet.Applet;
class Example extends Applet implements ActionListener
{
TextField txt = new TextField(10);
Button goButton = new Button("Go");
String data = new String ();
public void init ()
{
add(txt);
add(goButton);
goButton.addActionListener(this);
}
public void actionPerformed (ActionEvent e)
{
String cmd = e.getActionCommand();
if (cmd.equals("Go"))
{
// preserve data
data = txt.getText();
repaint();
}
}
}
You should create an intermediate class that represents the data.
After the GUI has been filled in and the submit button clicked, parse the data and fill in the fields in your class.
For example:
public class MyData {
public String Name;
public String Address;
}
Then, fire a method in your calculation method that takes this class as a parameter:
public void Calculate(MyData data) {
...
}
For more advanced handling, look into "interfaces" in Java - that's the standard way this is done.

Categories