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)
Related
Desired: A "Test of the Tests"
Imagine there is some additional "sanity check" that could be performed after a test class completes all its tests that would indicate whether test execution as a whole executed successfully. This final sanity check could possibly use some aggregated information about the tests. Just as a crude example: The number of calls to a shared method is counted, and if the count is not above some minimum expected threshold after all tests complete, then it is clear that something is wrong even if all the individual tests pass.
What I have described is probably in some "grey area" of best practices because while it does violate the doctrine of atomic unit tests, the final sanity check is not actually testing the class being tested; rather, it is checking that test execution as a whole was a success: A "test of the tests," so-to-speak. It is additional logic regarding the tests themselves.
This Solution Seems Bad
One way to accomplish this "test of tests" is to place the sanity check in a static #AfterClass method. If the check fails, one can call Assert.fail(), which actually works (surprisingly, since I presumed it could only be invoked from within methods annotated with #Test, which by nature must be instance methods, not static):
public class MyTest {
[...]
#AfterClass
public static void testSufficientCount() {
if (MyTest.counterVariable < MIN_COUNT) {
Assert.fail("This fail call actually works. Wow.");
}
}
}
There are many reasons why this solution is a kludge:
Assume there are N tests in total (where a "test" is an instance method annotated with #Test). When Assert.fail() is not called in #AfterClass, N tests in total are reported by the IDE, as expected. However, when Assert.fail() is called in #AfterClass, N + 1 tests in total are reported by the IDE (the extra one being the static #AfterClass method). The additional static method was not annotated with #Test, so it should not be counted as a test. Further, the total number of tests should not be a function of whether some tests pass or fail.
The #AfterClass method is static by definition. Therefore, only static members are accessible. This presents a problem for my specific situation; I will leave this statement without elaboration because the explanation is out of the scope of the question, but basically it would be most desirable if only instance members were used.
[Other reasons too...]
Is There a Better Way?
Is there a way to implement this "test of tests" that is considered good and common practice? Does JUnit 4 support adding some kind of logic to ensure a group of unit tests within a class executed properly (failing in some way if they did not)? Is there a name for this thing I have called a "test of tests"?
About variable number of tests
I don't think there is a valid solution ...
About static fields
I tried to follow your example and, if I understood well, with a combination of Verifier, TestRule and ClassRule it is possible to use only the instance fields of the test class
Here my code from which to take a cue:
public class ATest {
public int countVariable = 0;
private static class MyVerifier extends Verifier {
public int count = 0;
#Override
protected void verify() throws Throwable {
assertTrue(count < 1); // cause new failed test
// assertTrue(count >= 1); // it's all ok
}
}
#ClassRule
public static MyVerifier v = new MyVerifier();
private class MyRule implements TestRule {
ATest a;
MyVerifier v;
public MyRule(ATest a, MyVerifier v) {
this.a = a;
this.v = v;
}
#Override
public Statement apply(Statement base, Description description) {
try {
base.evaluate();
this.v.count = a.countVariable;
} catch (Throwable ex) {
Logger.getLogger(ATest.class.getName()).log(Level.SEVERE, null, ex);
}
return base;
}
}
#Rule
public MyRule rule = new MyRule(this, v);
#org.junit.Test
public void testSomeMethod() {
countVariable++; // modifies instance counter
assertTrue(true);
}
#org.junit.Test
public void testSomeMethod2() {
countVariable++; // modifies instance counter
assertTrue(true);
}
}
Having said that
"test of tests" isn't consider a common and good practice because, as you know, it violates at least two of five principles of the FIRST rule(see Cleean code from Uncle Bob Martin): tests must be
F: Fast
I: Indipendent
R: Repeteable
S: Self-validating
T: Timely (linked to TDD practice)
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
Just a question from a noob: how do I avoid huge main (in case of JavaFX, start) methods? I tend to create one-class projects but I know that's incorrect. Basically I do not know when to create dedicated classes for specific tasks.
I hope this question is not so stupid.
It's a not a stupid question. From what you've said, you might not need other classes. You may just need methods.
Lets look at a simple example:
public class MyClass {
public static void main(String[] args) {
int i = 4 + 2;
System.out.println(4 + 2);
}
}
Easy, right? But now, what if it gets harder.
public class MyClass {
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
int k = i + (7 / 2) * 3 / 14;
System.out.println(i + " " + k);
}
}
}
Now obviously, this isn't actually harder. But notice how there is a pattern? We take every number 0-9, and add (7 / 2) * 3 / 14. This can be moved into a method:
int getNumber(int i) {
return i + (7 / 2) * 3 / 14);
}
Now, our code looks much cleaner, as we don't have to deal with any addition or division or multiplication
public class MyClass {
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
int k = getNumber(i);
System.out.println(i + " " + k);
}
}
}
This example might seem dumb, because it involves a very easy math problem, but the point is: If you have something that you do repeatedly, put it in a method.
Note:
Methods can also be used to split up a large function. When in doubt, divide and conquer!
See this:
void run() {
getInput();
tick();
render();
}
Is much cleaner than something like this:
void run() {
Scanner reader = new Scanner(System.in);
System.out.println("Enter a number: ");
String string = reader.nextString();
MyObject obj = new MyObject();
obj.doSomething(string);
obj.render();
}
If you looked at that code you'd have no idea what it was doing! But the first example you would, because it divides into methods that clearly identify what they do.
Anyway, about classes:
Google OOP! There are tons of great resources. For most classes, you can think of them as a container. You could create a class, Wallet, that would contain Coins and manipulate it (think spend, remove, add).
There is no stupid question :)
You ask about Oriented Object Programming concept.
In Java, C++ or Php Object, the purpose is to store your code into logical aera. Immagine your code like life. Immagine everything act like an object.
For example, your program is simulating car.
In your code you will have an class Car, then a class Engine, then class BMW that inherit from Car and Car who is containing a instance of Engine.
In internet (use google) you will find a lots of explanation about how OOP work. All of this will explain this much better than i will.
If you have any question, you are welcome :)
This is my opinion that I've developed over the course of learning to program. Though my background is moreso with perl scripting and not oop
Separate the presentation from the data/logic.
Meaning, everything should be in classes (or function), and from the main thread you merely pass the object (or function) data, and you get data the same way.
If it does a specific set of tasks, make a class out of it.
If it could be used for other purposes make a class out of it.
If it does a specific operation, make a function out of it.