Is there a JUnit equivalent to NUnit's testcase attribute? - unit-testing

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 ...
}

Related

Using partial shape for unit testing with typescript

Let's say i want to unit test a function in typescript.
This function use an "option" type (object) parameter with a complex shape.
interface option {
param1 : string
param2 : number
param3 : {
param4 : string
param5 : boolean
}
.
.
.
param15 : string
}
const functionToTest = (opt:option)=>{
...do stuff with option
}
Now let say i want to write a unit test that mimic the correct behaviour of functionToTest when param1 change, ignoring the other parameter that have no influence on the result.
It's my understanding that to make my test more resilient, i can just write in plain JS
const option1 = {
param1 : "foo"
}
and do my testing
expect(functionToTest(option1)).to.be.true;
However, if i write my test with typescript, i will have to write a full option1 object with all of the interface (dummy) members, althought most will be ignored, and it will divert the reader from the true goal of the test.
Are there workarounds around this or something i should change in my thinking ?
You can take advantage of typescript's Partial for this.
interface YourInterface {
prop: string;
foo: number;
}
const data: Partial<YourInterface> = {
prop: 'value'
};
// service is an instance of SomeService
service.sendData(<YourInterface> data);
class SomeService {
sendData(data: YourInterface) {
}
}
In my tests, I use the as type assertion to pass in partial objects to a function.
const options = {
param1: 'param1',
param2: 22
} as Option;
expect(functionToTest(options)).to.be.true;
you may declare params as optional.
interface option {
param1 : string
param2? : number
param3? : {
param4 : string
param5 : boolean
}
.
param15? : string
}
I'm using the Parameters Typescript utility to get the type directly from the function I'm testing:
const toBeTested = (opts) => { ... };
type MockParams = Parameters<typeof toBeTested>[0];
it('should work', () => {
expect(toBeTested(foo as MockParams)).toBe(true);
});

GMock: Overriding a default expectation

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());
}

What is meant by parameterization?

While reading one of the articles for Data Driven Testing, I came across a term 'parametrization of a test'. Could someone explain to me what is meant by parameterization here?
Let's see an example with TestNG. Suppose you have function SomeClass.calculate(int value). You want to check the results the function returns on different input values.
With not-parametrized tests you do something like this:
#Test
public void testCalculate1()
{
assertEquals(SomeClass.calculate(VALUE1), RESULT1)
}
#Test
public void testCalculate2()
{
assertEquals(SomeClass.calculate(VALUE2), RESULT2)
}
With parametrized test:
//This test method declares that its data should be supplied by the Data Provider
//named "calculateDataProvider"
#Test(dataProvider = "calculateDataProvider")
public void testCalculate(int value, int result)
{
assertEquals(SomeClass.calculate(value), result)
}
//This method will provide data to any test method that declares that its Data Provider
//is named "calculateDataProvider"
#DataProvider(name = "calculateDataProvider")
public Object[][] createData()
{
return new Object[][] {
{ VALUE1, RESULT1 },
{ VALUE2, RESULT2 },
};
}
This way, TestNG engine will generate two tests from testCalculate method, providing parameters from array, returned by createData function.
For more details see documentation.

Moq in unit Testing

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.

NUnit parameterized tests with datetime

Is it not possible with NUnit to go the following?
[TestCase(new DateTime(2010,7,8), true)]
public void My Test(DateTime startdate, bool expectedResult)
{
...
}
I really want to put a datetime in there, but it doesn't seem to like it. The error is:
An attribute argument must be a constant expression, typeof expression
or array creation expression of an attribute parameter type
Some documentation I read seems to suggest you should be able to, but I can't find any examples.
You can specify the date as a constant string in the TestCase attribute and then specify the type as DateTime in the method signature.
NUnit will automatically do a DateTime.Parse() on the string passed in.
Example:
[TestCase("01/20/2012")]
[TestCase("2012-1-20")] // Same case as above in ISO 8601 format
public void TestDate(DateTime dt)
{
Assert.That(dt, Is.EqualTo(new DateTime(2012, 01, 20)));
}
I'd probably use something like the ValueSource attribute to do this:
public class TestData
{
public DateTime StartDate{ get; set; }
public bool ExpectedResult{ get; set; }
}
private static TestData[] _testData = new[]{
new TestData(){StartDate= new DateTime(2010, 7, 8), ExpectedResult= true}};
[Test]
public void TestMethod([ValueSource("_testData")]TestData testData)
{
}
This will run the TestMethod for each entry in the _testData collection.
Another alternative is to use a more verbose approach. Especially if I don't necessarily know up front, what kind of DateTime() (if any...) a given string input yields.
[TestCase(2015, 2, 23)]
[TestCase(2015, 12, 3)]
public void ShouldCheckSomething(int year, int month, int day)
{
var theDate = new DateTime(year,month,day);
....
}
...note TestCase supports max 3 params so if you need more, consider something like:
private readonly object[] testCaseInput =
{
new object[] { 2000, 1, 1, true, "first", true },
new object[] { 2000, 1, 1, false, "second", false }
}
[Test, TestCaseSource("testCaseInput")]
public void Should_check_stuff(int y, int m, int d, bool condition, string theString, bool result)
{
....
}
You should use the TestCaseData Class as documented: http://www.nunit.org/index.php?p=testCaseSource&r=2.5.9
In addition to specifying an expected result, like:
new TestCaseData(12, 4).Returns(3);
You can also specify expected exceptions, etc.:
new TestCaseData(0, 0)
.Throws(typeof(DivideByZeroException))
.SetName("DivideByZero")
.SetDescription("An exception is expected");
It seems that NUnit doesn't allow the initialization of non-primitive objects in the TestCase(s). It is best to use TestCaseData.
Your test data class would look like this:
public class DateTimeTestData
{
public static IEnumerable GetDateTimeTestData()
{
// If you want past days.
yield return new TestCaseData(DateTime.Now.AddDays(-1)).Returns(false);
// If you want current time.
yield return new TestCaseData(DateTime.Now).Returns(true);
// If you want future days.
yield return new TestCaseData(DateTime.Now.AddDays(1)).Returns(true);
}
}
In your testing class you'd have the test include a TestCaseSource which directs to your test data.
How to use: TestCaseSource(typeof(class name goes here), nameof(name of property goes here))
[Test, TestCaseSource(typeof(DateTimeTestData), nameof(GetDateTimeTestData))]
public bool GetDateTime_GivenDateTime_ReturnsBoolean()
{
// Arrange - Done in your TestCaseSource
// Act
// Method name goes here.
// Assert
// You just return the result of the method as this test uses ExpectedResult.
}
Nunit has improved and implicitly tries to convert the attribute arguments.
See doc: NUnit3 Doc - see note
This works:
[TestCase("2021.2.1", ExpectedResult = false)]
[TestCase("2021.2.26", ExpectedResult = true)]
public bool IsDate(DateTime date) => date.Date.Equals(new DateTime(2021, 2, 26));
Take care to use english culture format for DateTime string arguments.