I'm building an automatic game client that is supposed to make moves against me in a 4-Wins-Game. For making a move it should chose a column and send that chosen column by calling the move() function to my server.
public class AutomaticGameClient {
private String userName;
private String userPassword;
public AutomaticGameClient(String userName, String userPassword) {
this.userName = userName;
this.userPassword = userPassword;
}
public int makeMove() {
columnNo = 0;
move(columnNo);
return columnNo;
}
}
Right now it always simply moves by making the next move in the first row (columnNo = 0). This works.
Now I have to test that function, but I don't want to test the move() part. I only want to assert, that it's returning 0:
#Test
public void whenMakeMove_columnNoIsZero() {
AutomaticGameClient agcY = new AutomaticGameClient("Georg1", "geheim1");
int rowMoved = agcY.makeMove();
assertEquals(rowMoved, 0);
}
When I run this test, I get org.java_websocket.exceptions.WebsocketNotConnectedException, because move(columnNo) is trying to start a connection to my socket. So is there a way to skip this part of the function under test?
"So is there a way to skip this part of the function under test?" - Yes. One could create a partial mock/spy of the unit under test and then mock the move(...)-method. For more details please refer to this posts by Victor Grazi and its answers.
In this concrete situation, however, the cleaner solution would be to move socket-related code to a separate service. A unit should be tested as a unit and thus we should use mocks seldomly and only if no other possibility exists. This, however, is a boundary between units, thus socket-communication should be moved in a separate unit for better testability. Please notice that I do not say that each class is a unit. A unit can be composed of multiple classes. But one class should not be composed of multiple units since we then have to resort to solutions like partial mocks for the unit under test. In my opinion, mocking the unit under test is always a red flag.
Related
I'm studying to be a Java developer and right now I'm learning test driven development, which means that im very new to JUnit and Mockito.
I've been struggling for a while now and I'm stuck.
I have no idea how to test this particular method that has no arguments, no return value and a randomizer.
Old logic:
public void getPlayerToStart(int randomNr) {
if (randomNr == 1) {
currentPlayer = p1;
opponentPlayer = p2;
} else {
currentPlayer = p2;
opponentPlayer = p1;
}
}
Old test
#Test
void testSetCurrentPlayerSetToPlayer1() {
gameEngine.getPlayerToStart(1);
assertEquals(gameEngine.getP1(), gameEngine.getCurrentPlayer());
assertEquals(gameEngine.getP2(), gameEngine.getOpponentPlayer());
}
#Test
void testSetCurrentPlayerSetToPlayer2() {
gameEngine.getPlayerToStart(2);
assertEquals(gameEngine.getP2(), gameEngine.getCurrentPlayer());
assertEquals(gameEngine.getP1(), gameEngine.getOpponentPlayer());
}
New logic:
public void getPlayerToStart() {
Random rand = new Random();
int randomNr = rand.nextInt(2) + 1;
if (randomNr == 1) {
currentPlayer = p1;
opponentPlayer = p2;
} else {
currentPlayer = p2;
opponentPlayer = p1;
}
}
I'm not sure how to be able to test the getPlayerToStart() without the argument "randomNr".. Can someone please just point me in the right direction!
Thanks in advance.
Always to please be keeping in mind that the thought "gee, this is hard to test" is TDD trying to scream at you that the design needs review.
I have no idea how to test this particular method that has no arguments, no return value and a randomizer.
Random numbers are a side effect, like I/O or time, and should be handled that way in your design.
Which is to say, if you are doing TDD, one of the things you should be recognizing is that the source of randomness is an input to your system; it's part of the imperative shell which is provided by your test harness when running tests, and is provided by your composition root in production.
The testable approach would separate "generate a seed" from "compute a state from the seed"; unit tests are great for the latter bit, because pure functions are really easy to test. Generating random numbers is state of sin level hard to test, but with some design you can simplify the code around it to the point that it "obviously has no deficiencies".
You may also want to review Writing Testable Code, by Misko Hevery, or Tales of the Fischer King.
another solution could be a strict interpretation of the single responsibility pattern: a class providing business logic sould not be responsible to create or acquire its dependencies. This leads to the concept of dependency injection:
class CodeUnderTest {
private final Random rand;
public CodeUnderTest(#NotNull Random rand){
this.rand = rand;
}
public void getPlayerToStart() {
int randomNr = rand.nextInt(2) + 1;
if (randomNr == 1) {
currentPlayer = p1;
opponentPlayer = p2;
} else {
currentPlayer = p2;
opponentPlayer = p1;
}
}
}
You'd need to enhance your Test to this:
class CodeUnderTestTest{
private final Random fakeRandom = new Random(1);
private CodeUnderTest cut;
#Before
public void setup(){
cut = new CodeUnderTest(fakeRandom);
}
// your test code relying on the repeatable order
// of Random object initialized with a fix seed.
}
You also need to change all places in your code where you instantiate CodeUnderTest to add a Random object without seed.
This looks like a downside at first but it provides the possibility to have only one instance of Random throughout your code without implementing the Java Singelton Pattern.
You could gain even more control if you replace the Random object with a mock. The easiest way to do that is to use a mocking framework like Mockito:
class CodeUnderTestTest{
#Rule
public MockitoRule rule = MockitoJUnit.rule();
#Mock
private Random fakeRandom;
// you could use #InjectMocks here
// instead of the setup method
private CodeUnderTest cut;
// This will NOT raise compile errors
// for not declared or not provided
// constructor arguments (which is bad in my view).
#Before
public void setup(){
cut = new CodeUnderTest(fakeRandom);
}
#Test
void testSetCurrentPlayerSetToPlayer1() {
doReturn(0).when(fakeRandom).nextInt(2);
cut.getPlayerToStart(1);
assertEquals(cut.getP1(), cut.getCurrentPlayer());
assertEquals(cut.getP2(), cut.getOpponentPlayer());
}
}
Move the call to new Random() into its own method, like this.
You can rewrite your getPlayerToStart method to use the other one, to save duplicated code (but you don't need to).
public void getPlayerToStart() {
Random rand = makeRandom();
int randomNumber = rand.nextInt(2) + 1
getPlayerToStart(randomNumber);
}
public Random makeRandom() {
return new Random();
}
Now you can use Mockito to
make a mock Random object;
make a spy of your class, which is the object you're going to test;
stub the makeRandom method of your spy, so that it returns your mock Random;
stub the mock Random so that it returns whichever value you like, in each test.
After that, you can write a test in which player 1 is expected to start, and another test in which player 2 is expected to start.
I agree with who says that you should use dependency injection and have your own abstraction (in this way you could mock the collaborator).
But, creating the abstraction you're simply moving the responsibility (and the test problem) elsewhere.
Did you know about the Random constructor that takes an integer argument called "seed"? Using the same seed you will have always the same sequence of results.
See: https://stackoverflow.com/a/12458415/5594926
I have a generel question about Unit testing. I have read some guides about unit testing, however i still have one question. What parts of my code do i have to test? For example the class bellow has some variables to be set and a list that is frequently filled, but does it make sense to test them in a JUnitClass? Which part would you test?
public class Bill implements interfaces.Bill {
int billNumber;
Set<Scanable> scans = new LinkedHashSet();
public Bill(int billNumber) {
this.billNumber = billNumber;
}
public void addItem(Scanable s) {
scans.add(s);
}
#Override
public float getSum() {
int sum = 0;
for(Scanable x : this.scans) {
sum += x.getPrice();
}
return sum;
}
#Override
public Set<Scanable> getItems() {
return scans;
}
}
i would at least write tests for
public void addItem(Scanable s){
scans.add(s);
}
#Override
public float getSum() {
int sum = 0;
for(Scanable x : this.scans){
sum+=x.getPrice();
}
return sum;
}
the reason is not primary to verify the current functionality, but more to be prepared for future changes. lets say, you decide at some point to not initialize the field scans directly and have the possibility to run into a NPE, then your tests should expose this and you can react quite fast.
In general, unit test is to test the logical function. Because those function will have side effect after you modify it.
If your getter and setter are just assign value and return value, there's no need to write your unit test.
I personally wouldn't write any unit tests for setters and getters, unless your setters() and getters() contain some programmatic business logic i.e. something getting computed when the setter()/getter() are called.
For rest others methods the UT cases are must.
In some companies, the code coverage is very strict and to adhere to the process, we may have to write UT for getters() & setters() also. Although its not a bad idea to always write :-)
I'm having trouble with learning how to write and use my own classes. For example;
import java.text.NumberFormat;
public class BikeCommute {
private String route;
private double distanceTraveled;
private double timeRequired;
private String dateTraveled;
private String mode;
private double gallonsSaved;
final private int mpg = 25;
public BikeCommute(String mode, String dateTraveled, String route,
double distanceTraveled, double timeRequired)
{
mode = this.mode;
route = this.route;
distanceTraveled = this.distanceTraveled;
timeRequired = this.timeRequired;
dateTraveled = this.dateTraveled;
}
public double gallonsCalculated(){
gallonsSaved = distanceTraveled/mpg;
return gallonsSaved;
}
public double getGallons(){
return gallonsSaved;
}
public String toString(){
return mode + route + distanceTraveled + timeRequired + dateTraveled + gallonsSaved;
}
}
I'm trying to write a class called BikeCommute that will read in the route, mode of transportation, distance traveled, time required, and date that the trip was traveled, calculate how many gallons of gas were saved by dividing the distance traveled by the miles per gallon, and output the route, mode, distance traveled, time required, date traveled, and gallons saved. This, however, returns nullnull0.0null0.0 when I run it. Any thoughts?
Assignment is from right to left. Replace
mode = this.mode;
with
this.mode = mode
Same for the other field variables in BikeCommute
You have these the wrong way around:
mode = this.mode;
Should be:
this.mode = mode;
Your question is about a specific problem in this specific class; however, you should consider the general problem too.
If you have problems constructing or using your own classes, it's probably because you have confused the building of the class with the using of the class. Actually, you can get much better results if you "use the class" before you "build the class". I know that this sounds like nonsense, but it is the driving idea behind test driven development, which is one of the more effective ways to write robust usable programs.
Consider looking into JUnit and learn how to setup a "test" directory. I also recommend you minimally learn "just enough" maven to automate this. Don't start off trying to be a JUnit or Maven virtuoso. Cut-and-paste is fine for beginning in this area.
Then you can write your test first:
public void testBikeCommute() {
BikeCommute commute = new BikeCommute(...);
Assert.assertEquals(5, commute.getGallons());
}
Now you can see that your design is pretty odd, as most of my commutes don't have Gallons. As you attempt to "use" your software before you write it, you might find that your "commute" is really a comparison between two theoretical commutes, one in a car, and one on a bike.
public void testCommuteSavings() {
BikeCommute bike = new BikeCommute(...);
CarCommute car = new CarCommute(...);
SavingsCalculator calculator = new Calculator(car, bike);
Assert.assertEquals(5, calcuator.getSavedGallons());
}
This "use first" technique can allow you to develop a much cleaner representation of your problem, and with a toolkit like JUnit, can even become an automated testing strategy. Also it makes some items pretty easy to test, like
public void testBikeCommuteUsesZeroGallons() {
BikeCommute bike = new BikeCommute();
Assert.assertEquals(0, bike.getGallonsUsed());
}
Cheers
So I'm tesing using Junit, quite new to it.
I am trying to test methods in a class called SetOfUsers as follows:
#Test
public void testFindUserByName() {
System.out.println("findUserByName");
String name = "";
SetOfUsers instance = new SetOfUsers();
User expResult = null;
User result = instance.findUserByName(name);
assertEquals(expResult, result);
// TODO review the generated test code and remove the default call to fail.
}
So I wanted to check the name of a user entered in Bob for instance in the name string like this
String name = "Bob";
since I have a user called Bob in the setOfUsers class.
The output window displays this message
Failed: expected:<null> but was:<Staff name:Bob, Staff pass:abc123>
What can I do to make this a pass?
Read about BDD, this is very nice technique for making tests easy to write and understand (read)
Test-driven development is a software development methodology which essentially states that for each unit of software, a software developer must:
define a test set for the unit first;
then implement the unit;
finally verify that the implementation of the unit makes the tests succeed.
Well written test should have GivenWhenThen sections
(Given) some context
(When) some action is carried out
(Then) a particular set of observable consequences should obtain
This style is known as SpecificationByExample
Given-When-Then is a style of representing tests - or as its advocates would say - specifying a system's behavior using SpecificationByExample.
Example test
#Test
public void testFindUserByName() {
// given
SetOfUsers instance = new SetOfUsers();
// when
User result = instance.findUserByName("Bob");
// then
assertEquals("Bob", result.getName());
}
Nice to read:
Arrange Act Assert Alternatives
Maintainable Tests
This test is always going to fail because the last line is
fail("The test case is a prototype.");
The reason your test is failing now is because of the line above,
assertEquals(expResult, result);
You are setting your expected result to null and the result you are getting from the name, "", is probably an empty String as well from that error message. You need to have expResult to be the same as what you expect instance.findUserByName("Bob") to return. However, unless you initialize the instance to be set with a User Object the objects will not match, so it might be better to either mock it to return a pre-created User object so they match, or create a User object with the same properties as the one you expect to be returned check the fields of the User Object returned and the User object you created to be sure they match.
If you want to check for what the user for Bob is, change the code to this:
#Test
public void testFindUserByName() {
System.out.println("findUserByName");
String name = "Bob";
SetOfUsers instance = new SetOfUsers();
User expResult = <Create an object you expect instance.findUserByName("Bob") to return>;
User result = instance.findUserByName(name);
//Check fields here.
assertEquals(expResult.getUserName(), result,getUserName());
// TODO review the generated test code and remove the default call to fail.
}
You can't test for null using assertEquals().
To test for null, use:
assertNull(result);
I don't understand the question, but if you want to search for "Bob" why you initialize name=""? The test should be:
#Test
public void testFindUserByName() {
//Create SetOfUsers
//Add new User with name Bob
//FindByUsername("Bob")
//AssertEqual(User.getName(), "Bob")
}
As an exercise, I need to learn to write tests on the following class:
package bankAccount;
public class CurrentAccount {
int account[];
int lastMove;
CurrentAccount() {
lastMove = 0;
account = new int[10];
}
public void deposit(int value) {
account[lastMove] = value;
lastMove++;
}
public void draw(int value) {
account[lastMove] = value;
lastMove++;
}
public int settlement() {
int result = 0;
for (int i=0; i<account.length; i++) {
result = result + account[i];
}
return result;
}
public static void main(String args[]) {
CurrentAccount c = new CurrentAccount();
c.deposit(10);
}
}
I am relatively new to Unit testing, and a lot of the tutorials simply cover how to do tests for simple Mathematical operators (e.g. add, subtract etc). Can anyone recommend good resources for doing Unit testing of more complex functions? Am I best off using
http://junit.sourceforge.net/javadoc/org/junit/Assert.html
and working from there?
You should be testing against the specification of the object e.g.
what's the starting balance ?
what's the balance after I add £10 ?
can I go overdrawn ?
etc. All the above should be specified prior to writing the class (otherwise, how do you know what to write?)
I would create a test method for each of these scenarios, perform a setup and the action, and then use one (or more, if necessary) asserts to determine that all is well. Don't forget that in some cases you may be testing that an exception is thrown, and consequently you will want to check for a break in control flow. That wouldn't use assert.
Here's a possible example (imports etc. omitted)
public void testBalanceAfterTenPoundDeposit() {
// note the interface/impl separation so I can test different
// implementations with the same interface (this is Test By Contract)
CurrentAccount ca = new CurrentAccountImpl();
// check the starting balance
Assert.assertEquals(ca.settlement(), 0);
// deposit
ca.deposit(10);
// do I have £10 ?
Assert.assertEquals(ca.settlement(), 10);
}
It's important to note that this sort of testing should really be focused on the component (unit) as a black box. That is, the test should really be agnostic to the implementation and you wouldn't explicitly test the array implementation. I should be able to insert my own implementation (or rewrite yours) and the tests should remain working (that's the principle of a regression test).
Having said that, if you know of obvious limitations of the implementation (e.g. your fixed size array) you should try and stress that (e.g. in this situation, perform 11 inserts)