Let us say I have a Service
public interface IAreaService
{
int CalculateArea(int x,int y);
int CalculateAreaTimesX(int x, int y, int ammount);
}
public class AreaService : IAreaService
{
public int CalculateArea(int x,int y)
{
return x*y;
}
public int CalculateAreaTimesX(int x, int y, int ammount)
{
return CalculateArea(x, y)*ammount;
}
}
With the relevant Unit tests
[TestMethod]
public void AreaService_GetArea_Test()
{
AreaService service = new AreaService();
int expected = 9;
int actual = service.CalculateArea(3, 3);
Assert.AreEqual(expected,actual,"The Calculate area does not work as expected");
}
[TestMethod]
public void AreaService_GetAreaMultiplyByX_TestTrueValue()
{
AreaService service = new AreaService();
int expected = 27;
int actual = service.CalculateAreaTimesX(3, 3, 3);
Assert.AreEqual(expected,actual);
}
Ok, so after running the Unit tests. I am sure that my method in question is working and life should be great.
But now I want to use the IAreaService in another class, and this is where i lose the light. Here is the implementation of the other class.
public class PriceCalculatorService
{
private readonly IAreaService _areaService;
public PriceCalculatorService(IAreaService areaService)
{
_areaService = areaService;
}
public double GetPrice(int x, int y, int times, double price)
{
return _areaService.CalculateAreaTimesX(x, y, times)*price;
}
}
If I ran the following unit test (My idea might be wrong on mocking here, and this is where the question comes in.
[TestMethod]
public void PriceCalculatorService_GetPrice_Test()
{
var IAreaServiceMock = new Mock<IAreaService>();
IAreaServiceMock.Setup(ism => ism.CalculateAreaTimesX(2, 2, 2)).Returns(8);
PriceCalculatorService priceCalc = new PriceCalculatorService(IAreaServiceMock.Object);
double expected = 20;
double actual = priceCalc.GetPrice(2, 2, 2, 2.50);
Assert.AreEqual(expected,actual);
}
Question
When i run all the unit tests mentioned above then everything is good. All of them pass. But let us say i need for some reason to change the AreaService.Calculate() method to the following
public int CalculateArea(int x,int y)
{
return x*y+2;
}
This means that my Unit test "AreaService_GetArea_Test()" will fail, like it should, but because of the Mocking used in the "PriceCalculatorService_GetPrice_Test()" test will still pass, because it seems that when you mock a Service then the actual code is not used(obviously). So my
PriceCalculatorService_GetPrice_Test is useless. But I use a stub then the unit test will fail, because it should.
So when to Mock, and when not to Mock ?
So my PriceCalculatorService_GetPrice_Test is useless.
No it's not. It's testing the code of GetPrice, and only the code of GetPrice. Seems reasonable to me.
There's not a lot to test in that method, but you are testing it. It would be better if you didn't have the same argument three times (using 1, 2, 3 would be better, for example) but you're testing it.
There's no reason why that test should break just because an implementation of the interface changed. You caught the change to AreaService in AreaService_GetArea_Test(), which is indeed where you should have caught it.
PriceCalculatorService_GetPrice_Test is testing GetPrice. It is testing if the return value of GetPrice is _areaService.CalculateAreaTimesX(x, y, times) multiplying price. That is the meaning of the test. So it's not useless at all.
GetPrice should depend on the result of CalculateAreaTimesX, not the logic of that method. So whatever the mock returns, it's all right for the test.
Related
In GMock, is it possible to replace a previously set expectation?
Assume, a test suite has a default expectation for a specific method call, which is what most test cases want:
class MyClass {
public:
virtual int foo() = 0;
};
class MyMock {
public:
MOCK_METHOD0(foo, int());
};
class MyTest: public Test {
protected:
void SetUp() {
EXPECT_CALL(m_mock, foo()).WillOnce(Return(1));
}
MyMock m_mock;
};
TEST_F(MyTest, myTestCaseA) {
EXPECT_EQ(1, m_mock.foo());
}
This is working fine. Some of the test cases, however, have different expectations. If I add a new expectation, as shown below, it does not work.
TEST_F(MyTest, myTestCaseB) {
EXPECT_CALL(m_mock, foo()).WillOnce(Return(2));
EXPECT_EQ(2, m_mock.foo());
};
I get this message:
[ RUN ] MyTest.myTestCaseB
/home/.../MyTest.cpp:94: Failure
Actual function call count doesn't match EXPECT_CALL(m_mock, foo())...
Expected: to be called once
Actual: never called - unsatisfied and active
[ FAILED ] MyTest.myTestCaseB (0 ms)
I understand why I am getting this. The question is how to cancel the default expectation, if a test case specifies its own? Does GMock allow it or what approaches can I use to achieve the intended behaviour?
No, there's no way to clear an arbitrary expectation. You can use VerifyAndClearExpectations to clear all of them, that's probably more than you want. I can think of several alternatives that avoid the issue:
You could work around your problem by simply calling m_mock.foo() once in advance, thus fulfilling the initial expectation.
TEST_F(MyTest, myTestCaseB) {
EXPECT_CALL(m_mock, foo()).WillOnce(Return(2));
(void)m_mock.foo();
EXPECT_EQ(2, m_mock.foo());
}
Another alternative is to change the expectation to have it return the value of a variable, then then update the variable prior to the test body, as described in the cookbook under Returning Live Values from Mock Methods. For example:
void SetUp() {
m_foo_value = 1;
EXPECT_CALL(m_mock, foo()).WillOnce(Return(ByRef(m_foo_value)));
}
TEST_F(MyTest, myTestCaseB) {
m_foo_value = 2;
EXPECT_EQ(2, m_mock.foo());
}
Yet another alternative is to specify the return value and the count separately.
void SetUp() {
ON_CALL(m_mock, foo()).WillByDefault(Return(1));
EXPECT_CALL(m_mock, foo()).Times(1);
}
Then, you only need to specify a new return value for the special test:
TEST_F(MyTest, myTestCaseB) {
ON_CALL(m_mock, foo()).WillByDefault(Return(2));
EXPECT_EQ(2, m_mock.foo());
}
Which approach is better: I tried to find it on web, but I couldn't get a better answer.
1.
public class OtherClass
{
public int Add(int x, int y)
{
return x + y;
}
}
public class TestClass
{
OtherClass oClass = new OtherClass();
public int Fun1()
{
return oClass.Add(1,2);
}
public int Fun2()
{
return oClass.Add(1, 2);
}
}
2.
public class TestClass
{
public int Fun1()
{
OtherClass oClass = new OtherClass();
return oClass.Add(1, 2);
}
public int Fun2()
{
OtherClass oClass = new OtherClass();
return oClass.Add(1, 2);
}
}
I think it depends on what you are trying to test.
If you're testing the effects of a sequence of functions being executed on the same class instance then you might want to create a single instance (such as stress testing)
But otherwise I'd say it's always better to create a new instance of the class in each test function to ensure that the context of each test is predictable. If your test methods shared an instance of a class, and one test method fails and corrupts the state of the object under test, your subsequent test may fail for no other reason than the state of the object under test was corrupted by the previous failed test (it might appear the multiple tests are failing when in fact only one of the early ones is a true failure).
Depends on the scenario, if the class is gonna be shared on multiple functions and there are no specific arguments needed to create an instance of that class then it's better of being at the class level.
Let's say you're using the Fun1 and Fun2 often, having the instance creation on the method will have instance creation overhead rather than it being at the class level having a single instance, or better yet, make it static or make it singleton if you're sure that it's going to be a single instance throughout the whole app.
One benefit of having it in the class level is if you're doing unit testing, you can make an interface like IOtherClass and Inject it in the constructor of TestClass.
It would look something like this.
public class OtherClass : IOtherClass
{
public int Add(int x, int y)
{
return x + y;
}
}
public class TestClass
{
IOtherClass oClass;
public TestClass(IOtherClass _oClass)
{
oClass = _oClass;
}
public int Fun1()
{
return oClass.Add(1,2);
}
public int Fun2()
{
return oClass.Add(1, 2);
}
}
You're better off having it as a field in the class rather than declaring a new one in each method. The reason for this is simple, there won't be a line of code in each method declaring the variable meaning that if your declaration statement changes you will only have to change it in one place, not every method. Also it will make your code easier to read and add to because this line won't be duplicated everywhere.
Just remember if that field needs to be disposed your class should implement the IDisposable interface.
Does mocking a method using mockito ensures that mocked method will never be called? I have Main class which contains some code i want to write unit tests for and i have one unit test class MainTest which contains unit tests for Main class.
eg:
Source Class:
package abc;
public class Main {
public int check1() {
int num = 10;
num = modify(num);
return num;
}
public int modify(int num) {
if (num % 10 == 0) return num / 10;
return -1;
}
}
Junit Test (using mockito)
package abc;
import junit.framework.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
import org.mockito.Mockito;
public class MainTest {
private static Main main;
#BeforeClass
public static void setUp() {
main = Mockito.mock(Main.class);
Mockito.when(main.modify(10)).thenReturn(5);
}
#Test
public void testCheck1() {
Test1 main1 = new Main();
int num = main.check1();
Assert.assertEquals(5, num);
}
}
This test is failing. Why?
EDITED
Because you didn't provide a behavior for check1(). ALL methods get mocked, so without you providing a behavior, check1() returns a default value for the return type of int, which is 0. Furthermore, check1() since it is mocked does not even get to call modify().
If you are trying to test a class, you never mock the Class Under Test. On rare occasion, you might have to Spy a class under test. Rather, you mock collaborators only.
I am guessing your example was a contrived one (I hope). But if you are writing and testing a class where you think you want to modify some internal method's behavior, I see two likely probabilities:
You may need to refactor the functionality of the method you want to mock-out into a collaborator class. Then it makes sense to go ahead and mock that behavior as a collaborator.
You may also may need to modify the API so that you can pass in what is going to change. In your case, check1() hard-codes the value it passes to modify(), which is why you are trying to mock modify(). If instead that value were a parameter to check1() or a settable field in class Main, then there wouldn't even be a need to use a mock at all.
The Problem with your Test is, that you do not use your newly created main1 object.
If you want to change the behaviour of your systen under test (SUT) you would normally do something like this:
#Test
public void testCheck1() {
Test1 main1 = new Main(){
public int modify(int num) {
return 5; // hard coded return value
}
};
int num = main1.check1();
Assert.assertEquals(5, num);
}
This creates a subclass of Main with a new implementation of the modify-method.
This is an important technique for replacing hard-to-test methods in your SUT. You would normally use it to avoid expensive remote calls or similar.
It is of course possible to use a Mockito spy like this:
#Test
public void testCheck1() {
Test1 main1 = spy(new Main());
stub(main1.modify(10)).toReturn(5);
int num = main1.check1();
Assert.assertEquals(5, num);
}
Though i am late,it might be useful to some one. Just to add to #VivaceVivo answer: when using spies please consider doReturn|Answer|Throw() family of methods for stubbing. Sometimes it's impossible or impractical to use when(Object) for stubbing spies. more info here
I've googled for JUnit test case, and it comes up with something that looks a lot more complicated to implement - where you have to create a new class that extends test case which you then call:
public class MathTest extends TestCase {
protected double fValue1;
protected double fValue2;
protected void setUp() {
fValue1= 2.0;
fValue2= 3.0;
}
}
public void testAdd() {
double result= fValue1 + fValue2;
assertTrue(result == 5.0);
}
but what I want is something really simple, like the NUnit test cases
[TestCase(1,2)]
[TestCase(3,4)]
public void testAdd(int fValue1, int fValue2)
{
double result= fValue1 + fValue2;
assertIsTrue(result == 5.0);
}
Is there any way to do this in JUnit?
2017 update: JUnit 5 will include parameterized tests through the junit-jupiter-params extension. Some examples from the documentation:
Single parameter of primitive types (#ValueSource):
#ParameterizedTest
#ValueSource(strings = { "Hello", "World" })
void testWithStringParameter(String argument) {
assertNotNull(argument);
}
Comma-separated values (#CsvSource) allows specifying multiple parameters similar to JUnitParams below:
#ParameterizedTest
#CsvSource({ "foo, 1", "bar, 2", "'baz, qux', 3" })
void testWithCsvSource(String first, int second) {
assertNotNull(first);
assertNotEquals(0, second);
}
Other source annotations include #EnumSource, #MethodSource, #ArgumentsSource and #CsvFileSource, see the documentation for details.
Original answer:
JUnitParams (https://github.com/Pragmatists/JUnitParams) seems like a decent alternative. It allows you to specify test parameters as strings, like this:
#RunWith(JUnitParamsRunner.class)
public class MyTestSuite {
#Test
#Parameters({"1,2", "3,4"})
public testAdd(int fValue1, int fValue2) {
...
}
}
You can also specify parameters through separate methods, classes or files, consult the JUnitParamsRunner api docs for details.
Apparently the correct answer is "No, there is no equivalent." And that's sad.
JUnit parameterized tests and theories (as mentioned here and in JUnit - How to test a method with different values?) both can get the job done, but nowhere nearly as cleanly. They are sadly complicated to write, and hard to read.
I hope that one day JUnit can add an easier, NUnit-like syntax. Seems like it shouldn't be that difficult; though perhaps lambdas are needed?
It might also be worthwhile to check out JUnit Theories and Datapoints.
They let you parametrize tests, but run an all-pairs type combination on your inputs.
You can have junit with parameters using zohhak
Usage example:
#RunWith(ZohhakRunner.class)
public class HelloWorldTest {
#TestWith({
"2, 1, 3",
"3, 5, 8"
})
public void should_add_numbers(int addend1, int addend2, int result) {
assertThat(addend1 + addend2).isEqualTo(result);
}
}
It's silly but here is the workaround that I have in the end. Use 4 lines instead one line.
#Test
public void testAdd1() {
testAdd(1,2);
}
#Test
public void testAdd2() {
testAdd(3,4);
}
private void testAdd(int fValue1, int fValue2)
{
double result= fValue1 + fValue2;
assertIsTrue(result == 5.0);
}
I have used a holding class to hold my test cases like this:
class FlexiTest {
String var1;
String var2;
double var3;
String var4;
MyObject var5;
double expected;
public FlexiTest(String var1, String var2, double var3, String var4, MyObject var5, double expected) {
super();
this.var1;
this.var2;
this.var3;
this.var4;
this.var5;
this.expected = expected;
}
Then setup a stream of my the test class objects like this:
static Stream<FlexiTest> provider(){
FlexiTest ft1 = new FlexiTest("1", "2", 3, "4", MyObject.A, 1.1);
FlexiTest ft2 = new FlexiTest("10", "20", 30, "40", MyObject.B, 11);
FlexiTest ft3 = new FlexiTest("100", "200", 300, "400", MyObject.C, 110);
return Stream.of(ft1, ft2, ft3);
}
Then annotated the Test method with #ParameterizedTest and #MethodSource with the stream of objects method name. Also null and empty checks:
#ParameterizedTest
#MethodSource("provider")
#NullSource
#EmptySource
public void ClientTest(FlexiTest ft)
{
... my test code ...
}
I've been working on a Java application where I have to use JUnit for testing. I am learning it as I go. So far I find it to be useful, especially when used in conjunction with the Eclipse JUnit plugin.
After playing around a bit, I developed a consistent method for building my unit tests for functions with no return values. I wanted to share it here and ask others to comment. Do you have any suggested improvements or alternative ways to accomplish the same goal?
Common Return Values
First, there's an enumeration which is used to store values representing test outcomes.
public enum UnitTestReturnValues
{
noException,
unexpectedException
// etc...
}
Generalized Test
Let's say a unit test is being written for:
public class SomeClass
{
public void targetFunction (int x, int y)
{
// ...
}
}
The JUnit test class would be created:
import junit.framework.TestCase;
public class TestSomeClass extends TestCase
{
// ...
}
Within this class, I create a function which is used for every call to the target function being tested. It catches all exceptions and returns a message based on the outcome. For example:
public class TestSomeClass extends TestCase
{
private UnitTestReturnValues callTargetFunction (int x, int y)
{
UnitTestReturnValues outcome = UnitTestReturnValues.noException;
SomeClass testObj = new SomeClass ();
try
{
testObj.targetFunction (x, y);
}
catch (Exception e)
{
UnitTestReturnValues.unexpectedException;
}
return outcome;
}
}
JUnit Tests
Functions called by JUnit begin with a lowercase "test" in the function name, and they fail at the first failed assertion. To run multiple tests on the targetFunction above, it would be written as:
public class TestSomeClass extends TestCase
{
public void testTargetFunctionNegatives ()
{
assertEquals (
callTargetFunction (-1, -1),
UnitTestReturnValues.noException);
}
public void testTargetFunctionZeros ()
{
assertEquals (
callTargetFunction (0, 0),
UnitTestReturnValues.noException);
}
// and so on...
}
Please let me know if you have any suggestions or improvements. Keep in mind that I am in the process of learning how to use JUnit, so I'm sure there are existing tools available that might make this process easier. Thanks!
It is true that if you are using JUnit 3, and you are testing whether a particular exception is thrown or not thrown within a method, you will need to use something like the try-catch pattern you define above.
However:
1) I'd argue that there is a lot more to testing a method with a void return value then checking for exceptions: is your method making the correct calls to (presumably mocked) dependencies; does it behave differently when the class is initialized with a different context or different sets of dependencies, etc. By wrapping all calls to that method, you make it hard to change other aspects of your test.
I'm also generally opposed to adding code and adding complexity if it can be avoided; I don't think it's a burden to have to put a try/catch in a given test when it's checking for exceptions.
2) Switch to JUnit 4! It makes it easy to check for expected exceptions:
#Test(expected=IndexOutOfBoundsException.class)
public void testIndexOutOfBoundsException() {
ArrayList emptyList = new ArrayList();
Object o = emptyList.get(0);
}
If you have the possibility, you should upgrade to JUnit 4.x.
Then your first example can be rewritten to:
#Test(expected=RuntimeException.class)
public void testTargetFunction() {
testObj.targetFunction (x, y);
}
The advantage here is that you can remove you the private UnitTestReturnValues callTargetFunction (int x, int y) method and use JUnit's built in support for expecting exceptions.
You should also test for specific exceptions instead.
Looks like you reimplemented most of JUnit :) In general you don't need to do it. You just call the function you want to call and compare results. If it throws an exception, JUnit will catch if for you and fail the test. If you expect an exception, either you can use the explicit annotation if you are using JUnit 4, or you can use the following pattern:
public void testThrows()
{
try {
obj.DoSth(); //this should throw MyException
assertFail("Expected exception");
} catch (MyException e) {
//assert the message etc
}
}
again, if obj.DoSth() throws a different exception JUnit will fail the test.
So to sum up, I am afraid I believe your approach is overcomplicated, sorry.
please correct me if I am wrong. As I understood from the provided code you're only checking if there may be an exception while executing the function. But you're actually not verifying, if the called functions "works" correctly unless the only way to end in case of an error would be an exception. I suggest writing additional tests like this:
public void testTargetFunctionSomeValue() {
int someValue = 0;
callTargetFunction(someValue, someValue);
assertTrue(verifyTargetFunction(someValue, someValue));
}
public boolean verifyTargetFucntion(int someValue, int someValue) {
// verify that execution of targetFunction made expected changes.
. . . . .
}
and the verifyTargetFunction would acutally check, if calling targetFunction would have made the expected changes - let's say to a database table by returning true or false.
Hope that helps.
Cheers,
Markus