Spock - Testing Exceptions with Data Tables - exception

How can exceptions be tested in a nice way (e.g. data tables) with Spock?
Example: Having a method validateUser that can throw exceptions with different messages or no exception if the user is valid.
The specification class itself:
class User { String userName }
class SomeSpec extends spock.lang.Specification {
...tests go here...
private validateUser(User user) {
if (!user) throw new Exception ('no user')
if (!user.userName) throw new Exception ('no userName')
}
}
Variant 1
This one is working but the real intention is cluttered by all the when / then labels and the repeated calls of validateUser(user).
def 'validate user - the long way - working but not nice'() {
when:
def user = new User(userName: 'tester')
validateUser(user)
then:
noExceptionThrown()
when:
user = new User(userName: null)
validateUser(user)
then:
def ex = thrown(Exception)
ex.message == 'no userName'
when:
user = null
validateUser(user)
then:
ex = thrown(Exception)
ex.message == 'no user'
}
Variant 2
This one is not working because of this error raised by Spock at compile time:
Exception conditions are only allowed in 'then' blocks
def 'validate user - data table 1 - not working'() {
when:
validateUser(user)
then:
check()
where:
user || check
new User(userName: 'tester') || { noExceptionThrown() }
new User(userName: null) || { Exception ex = thrown(); ex.message == 'no userName' }
null || { Exception ex = thrown(); ex.message == 'no user' }
}
Variant 3
This one is not working because of this error raised by Spock at compile time:
Exception conditions are only allowed as top-level statements
def 'validate user - data table 2 - not working'() {
when:
validateUser(user)
then:
if (expectedException) {
def ex = thrown(expectedException)
ex.message == expectedMessage
} else {
noExceptionThrown()
}
where:
user || expectedException | expectedMessage
new User(userName: 'tester') || null | null
new User(userName: null) || Exception | 'no userName'
null || Exception | 'no user'
}

The recommended solution is to have two methods: one that tests the good cases, and another that tests the bad cases. Then both methods can make use of data tables.
Example:
class SomeSpec extends Specification {
class User { String userName }
def 'validate valid user'() {
when:
validateUser(user)
then:
noExceptionThrown()
where:
user << [
new User(userName: 'tester'),
new User(userName: 'joe')]
}
def 'validate invalid user'() {
when:
validateUser(user)
then:
def error = thrown(expectedException)
error.message == expectedMessage
where:
user || expectedException | expectedMessage
new User(userName: null) || Exception | 'no userName'
new User(userName: '') || Exception | 'no userName'
null || Exception | 'no user'
}
private validateUser(User user) {
if (!user) throw new Exception('no user')
if (!user.userName) throw new Exception('no userName')
}
}

Here is the solution I came up with. It's basically Variant 3, but it uses a try/catch block to avoid using Spock's exception conditions (since those have to be top level).
def "validate user - data table 3 - working"() {
expect:
try {
validateUser(user)
assert !expectException
}
catch (UserException ex)
{
assert expectException
assert ex.message == expectedMessage
}
where:
user || expectException | expectedMessage
new User(userName: 'tester') || false | null
new User(userName: null) || true | 'no userName'
null || true | 'no user'
}
Some caveats:
You need multiple catch blocks to test different exceptions.
You have to use explicit conditions (assert statements) inside of try/catch blocks.
You can't separate your stimulus and responses into when-then blocks.

You can wrap your method call with a method that returns the message or the exception class, or a map of both...
def 'validate user - data table 2 - not working'() {
expect:
expectedMessage == getExceptionMessage(&validateUser,user)
where:
user || expectedMessage
new User(userName: 'tester') || null
new User(userName: null) || 'no userName'
null || 'no user'
}
String getExceptionMessage(Closure c, Object... args){
try{
return c.call(args)
//or return null here if you want to check only for exceptions
}catch(Exception e){
return e.message
}
}

Here's how I do it, I modify the when: clause to always throw a Success exception, that way you don't need separate tests or logic to tell whether to call thrown or notThrown, just always call thrown with the data table telling whether to expect Success or not.
You could rename Success to be None or NoException or whatever you prefer.
class User { String userName }
class SomeSpec extends spock.lang.Specification {
class Success extends Exception {}
def 'validate user - data table 2 - working'() {
when:
validateUser(user)
throw new Success ()
then:
def ex = thrown(expectedException)
ex.message == expectedMessage
where:
user || expectedException | expectedMessage
new User(userName: 'tester') || Success | null
new User(userName: null) || Exception | 'no userName'
null || Exception | 'no user'
}
private validateUser(User user) {
if (!user) throw new Exception ('no user')
if (!user.userName) throw new Exception ('no userName')
}
}
One extra thing I would change, would be to use a subclass for the failure exceptions too to avoid a Success being accidentally caught when you were really expecting a failure. It doesn't affect your example because you have an extra check for the message, but other tests might just test the exception type.
class Failure extends Exception {}
and use that or some other "real" exception instead of the vanilla Exception

I have solution which not distort your test workflow and you can analyze exception by content of dynamic object placed in where table
#Unroll
def "test example [a=#a, b=#b]"() {
given:
def response
def caughtEx
when:
try {
result = someAmazingFunctionWhichThrowsSometimes(a,b)
} catch (Exception ex) {
caughtEx = ex
}
then:
result == expected
if (exception.expected) {
assert caughtEx != null && exception.type.isInstance(caughtEx)
} else {
assert caughtEx == null
}
where:
a | b || exception | expected
8 | 4 || [expected: false] | 2
6 | 3 || [expected: false] | 3
6 | 2 || [expected: false] | 3
4 | 0 || [expected: true, type: RuntimeException] | null
}

Using the example from #AmanuelNega I had a try at this on the spock web console and saved the code at http://meetspock.appspot.com/script/5713144022302720
import spock.lang.Specification
class MathDemo {
static determineAverage(...values)
throws IllegalArgumentException {
for (item in values) {
if (! (item instanceof Number)) {
throw new IllegalArgumentException()
}
}
if (!values) {
return 0
}
return values.sum() / values.size()
}
}
class AvgSpec extends Specification {
#Unroll
def "average of #values gives #result"(values, result){
expect:
MathDemo.determineAverage(*values) == result
where:
values || result
[1,2,3] || 2
[2, 7, 4, 4] || 4.25
[] || 0
}
#Unroll
def "determineAverage called with #values throws #exception"(values, exception){
setup:
def e = getException(MathDemo.&determineAverage, *values)
expect:
exception == e?.class
where:
values || exception
['kitten', 1]|| java.lang.IllegalArgumentException
[99, true] || java.lang.IllegalArgumentException
[1,2,3] || null
}
Exception getException(closure, ...args){
try{
closure.call(args)
return null
} catch(any) {
return any
}
}
}
​

Here is an example of how I achieved it using #Unroll and the when:, then:, and where: blocks. It runs using all 3 of the tests with the data from the data table:
import spock.lang.Specification
import spock.lang.Unroll
import java.util.regex.Pattern
class MyVowelString {
private static final Pattern HAS_VOWELS = Pattern.compile('[aeiouAEIOU]')
final String string
MyVowelString(String string) {
assert string != null && HAS_VOWELS.matcher(string).find()
this.string = string
}
}
class PositiveNumberTest extends Specification {
#Unroll
def "invalid constructors with argument #number"() {
when:
new MyVowelString(string)
then:
thrown(AssertionError)
where:
string | _
'' | _
null | _
'pppp' | _
}
}

Related

SerializableError: Error serializing `.courses` returned from `getServerSideProps` in "/"

I am getting this error. Please help me to solve it.
error - SerializableError: Error serializing `.courses` returned from `getServerSideProps` in "/".
Reason: undefined cannot be serialized as JSON. Please use null or omit this value.
at isSerializable (C:\Users\Begim\Desktop\learn\anova\node_modules\next\dist\lib\is-serializable-props.js:39:19)
at C:\Users\Begim\Desktop\learn\anova\node_modules\next\dist\lib\is-serializable-props.js:46:66
at Array.every (<anonymous>)
at isSerializable (C:\Users\Begim\Desktop\learn\anova\node_modules\next\dist\lib\is-serializable-props.js:43:39)
at Object.isSerializableProps (C:\Users\Begim\Desktop\learn\anova\node_modules\next\dist\lib\is-serializable-props.js:67:12)
at Object.renderToHTML (C:\Users\Begim\Desktop\learn\anova\node_modules\next\dist\server\render.js:570:67)
at runMicrotasks (<anonymous>)
at processTicksAndRejections (node:internal/process/task_queues:96:5)
at async doRender (C:\Users\Begim\Desktop\learn\anova\node_modules\next\dist\server\base-server.js:687:38)
at async cacheEntry.responseCache.get.isManualRevalidate.isManualRevalidate (C:\Users\Begim\Desktop\learn\anova\node_modules\next\dist\server\base-server.js:796:28) {
page: '/'
}
Here is my code at is-serializable-props.js
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.isSerializableProps = isSerializableProps;
var _isPlainObject = require("../shared/lib/is-plain-object");
const regexpPlainIdentifier = /^[A-Za-z_$][A-Za-z0-9_$]*$/;
class SerializableError extends Error {
constructor(page, method, path, message){
super(path ? `Error serializing \`${path}\` returned from \`${method}\` in "${page}".\nReason: ${message}` : `Error serializing props returned from \`${method}\` in "${page}".\nReason: ${message}`);
}
}
exports.SerializableError = SerializableError;
function isSerializableProps(page, method, input) {
if (!(0, _isPlainObject).isPlainObject(input)) {
throw new SerializableError(page, method, "", `Props must be returned as a plain object from ${method}: \`{ props: { ... } }\` (received: \`${(0, _isPlainObject).getObjectClassLabel(input)}\`).`);
}
function visit(visited, value, path) {
if (visited.has(value)) {
throw new SerializableError(page, method, path, `Circular references cannot be expressed in JSON (references: \`${visited.get(value) || "(self)"}\`).`);
}
visited.set(value, path);
}
function isSerializable(refs, value, path) {
const type = typeof value;
if (// `null` can be serialized, but not `undefined`.
value === null || // n.b. `bigint`, `function`, `symbol`, and `undefined` cannot be
// serialized.
//
// `object` is special-cased below, as it may represent `null`, an Array,
// a plain object, a class, et al.
type === "boolean" || type === "number" || type === "string") {
return true;
}
if (type === "undefined") {
throw new SerializableError(page, method, path, "undefined cannot be serialized as JSON. Please use null or omit this value.");
}
if ((0, _isPlainObject).isPlainObject(value)) {
visit(refs, value, path);
if (Object.entries(value).every(([key, nestedValue])=>{
const nextPath = regexpPlainIdentifier.test(key) ? `${path}.${key}` : `${path}[${JSON.stringify(key)}]`;
const newRefs = new Map(refs);
return isSerializable(newRefs, key, nextPath) && isSerializable(newRefs, nestedValue, nextPath);
})) {
return true;
}
throw new SerializableError(page, method, path, `invariant: Unknown error encountered in Object.`);
}
if (Array.isArray(value)) {
visit(refs, value, path);
if (value.every((nestedValue, index)=>{
const newRefs = new Map(refs);
return isSerializable(newRefs, nestedValue, `${path}[${index}]`);
})) {
return true;
}
throw new SerializableError(page, method, path, `invariant: Unknown error encountered in Array.`);
}
// None of these can be expressed as JSON:
// const type: "bigint" | "symbol" | "object" | "function"
throw new SerializableError(page, method, path, "`" + type + "`" + (type === "object" ? ` ("${Object.prototype.toString.call(value)}")` : "") + " cannot be serialized as JSON. Please only return JSON serializable data types.");
}
return isSerializable(new Map(), input, "");
}
//# sourceMappingURL=is-serializable-props.js.map
I tried everything here advised on stackoverflow

How can I return two entity objects from web api?

What I am trying to do is getting two entity and returning from a single return using Json Object so getting this exception:-
Self referencing loop detected for property 'Job' with type 'System.Data.Entity.DynamicProxies
Here is what I am doing in code
[Route("api/Listing/GetAllList/{id:Guid}")]
[HttpGet]
public ResponseWrapper<GenericResponseModel> GetAllList(Guid id)
{
var heightSafety = database.HeightSafetyForms.Where(j => j.JobId == id).FirstOrDefault();
var chimneyTower = database.ChimneyTowerForms.Where(j => j.JobId == id).FirstOrDefault();
return ResponseService.ReturnResponse(() =>
{
if (heightSafety == null || chimneyTower == null)
{
return new GenericResponseModel(false, "Job could not be found.", null);
}
else
{
return new GenericResponseModel(true, string.Empty, Json(new
{
heightSafety = heightSafety,
chimneyTower = chimneyTower
}));
}
}, Request);
}
}
}
Created ModelHelper Class for ChimneyTower and HieghtSafety and assigned the values of the object of ChimneyTower to ChimneyTowerModelHelper object and then returned in the return statement

Using exceptions as default arguments in Kotlin

I'm writing a function in Kotlin to retrieve items of type T from a database.
The user can specify an action to be invoked if no matching results are found, otherwise an IllegalArgumentException is thrown:
fun get(
...,
onNoneFound: () -> T = throw IllegalStateException("No matching results found")
): T {
...
return when (results.size) -> {
0 -> onNoneFound.invoke()
1 -> ...
else -> chooseResult(...)
}
}
The issue I'm having is that whenever the function is invoked, it seems that the IllegalStateException is thrown before the function body is executed.
In a way, that makes sense, and I suppose a workaround could be:
fun get(
...,
onNoneFound: (() -> T)? = null
): T {
...
return when (results.size) -> {
0 -> if (onNoneFound == null) {
throw IllegalArgumentException("No matching results found")
} else {
onNoneFound.invoke()
}
1 -> ...
else -> chooseResult(...)
}
}
I was wondering if there is a more elegant/preferable solution to this problem - ideally where I do not have to make the function nullable and do a null check later. Is there a way of doing this with Kotlin's default argument syntax?
Edit:
It occurred to me that I can use the elvis operator for the null check which does make the code more elegant:
onNoneFound?.invoke() ?: throw IllegalArgumentException("No matching results found")
But I'm still curious if Kotlin has a built-in way of doing this without the null check.
You shouldn't build the exception directly. Try:
fun get(
...,
onNoneFound: () -> T = { throw IllegalStateException("No matching results found") }
): T {
...
return when (results.size) -> {
0 -> onNoneFound.invoke()
1 -> ...
else -> chooseResult(...)
}
}
The problem is that throw IllegalStateException(...) is a perfectly fine expression of type () -> T, just as it is an expression of any other type; but it throws the exception immediately, what you want is a lambda which will throw the exception when invoked. And that's { throw IllegalStateException(...) } in Kotlin, as
Roger Lindsjö's answer says.

grails exception: Tag [paginate] is missing required attribute [total]

I've the following method in my controller, that is used to list the Patient entities:
def list(Integer max) {
params.max = Math.min(max ?: 10, 100)
def roles = springSecurityService.getPrincipal().getAuthorities()
if(roles == 'ROLE_USER')
{
[patientInstanceList: Patient.findAllBySecUser(springSecurityService.getCurrentUser()), patientInstanceTotal: Patient.count()]
}
else if(roles == 'ROLE_ADMIN' || roles == 'ROLE_MANAGER')
{
[patientInstanceList: Patient.list(params), patientInstanceTotal: Patient.count()]
}
}
If I perform this method I have the exception
Tag [paginate] is missing required attribute [total]
But, if I use the following
def list(Integer max) {
params.max = Math.min(max ?: 10, 100)
[patientInstanceList: Patient.list(params), patientInstanceTotal: Patient.count()]
}
}
Everything works well. I see all the instances of Patient created. I only want that, based on role of user logged in, I can see a part of all the entities created. Why does this exception is raised?
I've found here Grails pagination tag error something similar, but no good answer was given
I'm not sure that you can ommit the return in a if statement. Another detail is that you're filtering your domain records in the ROLE_USER, but counting the total independent of this filter.
You can try this approach:
def list(Integer max) {
params.max = Math.min(max ?: 10, 100)
def roles = springSecurityService.getPrincipal().getAuthorities()
def model
//I think roles is a list so your equals will not work...
def admin = roles.find { it.authority == 'ROLE_ADMIN' || it.authority == 'ROLE_MANAGER' }
if(admin) {
model = [patientInstanceList: Patient.list(params), patientInstanceTotal: Patient.count()]
} else {
//createCriteria().list(params) will paginate...
def patientInstanceList = Patient.createCriteria().list(params) {
eq('secUser', springSecurityService.currentUser)
}
//totalCount will trigger a query without the limit, but applying your filter
model = [patientInstanceTotal: patientInstanceList.totalCount, patientInstanceList: patientInstanceList]
}
//and finally we return the model
//return model
//just to show that the return is optional
model
}

AttachAll exception: type arguments for method cannot be inferred from the usage. Try specifying the type arguments explicitly

Scenario:
Trying to call the .AttachAll method on a table in my LinqToSql DataContext object.
Here's the relevant simplified snippet:
public void Update(Customer cust){
MyDataContext db = new MyDataContext();
db.CustomerInvoices.AttachAll(cust.Invoices); //exception raised here!
db.Customer.Attach(cust);
}
Exception raised by the Compiler:
The type arguments for method
'System.Data.Linq.Table(Invoices).AttachAll(TSubEntity)(System.Collections.Generic.IEnumerable(TSubEntity))'
cannot be inferred from the usage. Try
specifying the type arguments
explicitly.
Question: What is the proper way to cast the collection properly? Any other solutions besides a cast?
Tf cust.Invoices already refers to instances of the CustomerInvoices table, just doing
db.Customers.Attach(cust); db.Update(); should be all you need to do.
If CustomerInvoices is a different type from Customer.Invoice, you'll probably need to iterate through the collection, and cast each one.
else if (((CheckBox)item.Cells[2].FindControl("ckbSelect")).Checked == true && ((Label)item.Cells[2].FindControl("lblIsInuse")).Text == "1")
{
RolePage objTemp = new RolePage();
objTemp = new Helper().GetRolePagebyID(roleId, Convert.ToInt32(item.Cells[0].Text));
rp.RoleId = objTemp.RoleId;
rp.PageId = objTemp.PageId;
rp.RolePageId = objTemp.RolePageId;
rp.CreatedOn = objTemp.CreatedOn;
rp.Timestamp = objTemp.Timestamp;
//rp.RoleId = roleId;
//rp.PageId = Convert.ToInt32(item.Cells[0].Text);
//rp.RolePageId =Convert.ToInt32(((Label)item.Cells[2].FindControl("lblRolePageId")).Text.Trim());
rp.IsNew = false;
rp.IsDeleted = false;
rp.UpdatedOn = DateTime.Now;
erp.Add(rp);
}
public string Save(Role objRole)
{
string message = string.Empty;
System.Data.Common.DbTransaction trans = null;
try
{
Objdb.Connection.Open();
trans = Objdb.Connection.BeginTransaction();
Objdb.Transaction = trans;
if (objRole.RoleId == 0)
{
Objdb.Roles.InsertOnSubmit(objRole);
}
else
{
Objdb.Roles.Attach(objRole, true);
Objdb.RolePages.AttachAll(objRole.RolePages.Where(a => a.IsNew == false && a.IsDeleted == false), true);
Objdb.RolePages.InsertAllOnSubmit(objRole.RolePages.Where(a => a.IsNew == true && a.IsDeleted == false));
Objdb.RolePages.DeleteAllOnSubmit(objRole.RolePages.Where(a => a.IsNew == false && a.IsDeleted == true));
}
Objdb.SubmitChanges();
trans.Commit();
message = "Record saved successfully.";
}
catch (Exception ex)
{
trans.Rollback();
message = "Error : " + ex.Message;
}
return message;
}