I have an abstract Record class that represents records in the database. Each record must have at least the following columns: id, created, updated.
I then extend the Record class to represent rows in specific tables. For example, i have the following classes that extend Record: Customer, Job, Location, and Company. In each of these i define a static "table_name" variable and static variables that represent their columns.
I'd like to be able to test these classes for basic functionality that all extensions of Record should have. I could write a test class for each one to test for these things but i would basically be copying and pasting those tests for each extension of Record class which doesn't seem right.
I thought about writing a test class and and using a data provider with these objects in an array but i wouldn't know which object would cause the failure if there was a failing test.
There's got to be a way of having some sort of TestAllExtensionsOfRecordClass test class and then run my objects through it and be able to tell which object caused a failure.
Suggestions?
Many unit testing frameworks support test class inheritance - you can create an abstract test superclass and all derived test classes will inherit and execute all tests in it. This allows you to define abstract test cases aka contract tests in that superclass. These are tests for your "basic functionality" that must remain constant regardless of the concrete implementation. So in your case you would have an abstract RecordTest containing all basic test cases and derived CustomerTest, JobTest, etc. which will execute these tests against their own implementation.
Related
I am writing a data export application that is used for many scenarios (Vendors, Customers, Cost Centers, REFX Contracts, etc).
In the end there are two main ways of exporting: save to file or call webservice.
So my idea was create an interface if_export, implement a class for each scenario.
The problem is, the call webservice code differs slightly at the point of the actual call: the called method has a different name each time.
My ideas for dealing with this so far are:
Abstract cl_webservice_export with subclasses for each scenario. Overwrite method containing the actual call.
cl_webservice_export with member type if_webservice_call. class for each scenario implementing if_webservice_call method call_webservice()
Dynamic CALL METHOD webservice_instance->(method_name) inside
concrete cl_webservice_export method containing the actual call and passing (method_name) to cl_webservice_export.
My code:
export_via_webservice is the public interface provided by cl_webservice_export or via if_export
METHODS export_via_webservice
IMPORTING
VALUE(it_xml_strings) TYPE tt_xml_string_table
io_service_consumer TYPE REF TO ztnco_service_vmsoap
RETURNING
VALUE(rt_export_results) TYPE tt_xml_string_table.
METHOD export_via_webservice.
LOOP AT it_xml_strings INTO DATA(lv_xml_string).
call_webservice(
EXPORTING
io_service = io_service_consumer
iv_xml_string = lv_xml_string-xmlstring
RECEIVING
rv_result = DATA(lv_result)
).
rt_export_results = VALUE #( BASE rt_export_results (
lifnr = lv_xml_string-xmlstring
xmlstring = lv_result ) ).
ENDLOOP.
ENDMETHOD.
Actual webservice call, overridden or provided by if_webservice_call
METHODS call_webservice
IMPORTING
io_service TYPE REF TO ztnco_service_vmsoap
iv_xml_string TYPE string
RETURNING
VALUE(rv_result) TYPE string.
METHOD call_webservice.
TRY.
io_service->import_creditor(
EXPORTING
input = VALUE #( xml_creditor_data = iv_xml_string )
IMPORTING
output = DATA(lv_output)
).
CATCH cx_ai_system_fault INTO DATA(lx_exception).
ENDTRY.
rv_result = lv_output-import_creditor_result.
ENDMETHOD.
How would you solve this problem, maybe there are other, better ways of doing it?
I know three common patterns to solve this question. They are, in ascending order of quality:
Individual implementations
Create one interface if_export, and one class that implements it for each web service export variant that you need, i.e. cl_webservice_export_variant_a, cl_webservice_export_variant_b, etc.
Major advantages are the intuitive simplistic class design and complete independence of the implementations that avoids accidental spillover from one variant to the other.
Major disadvantage are the probably massive portion of code duplication between the different variants, if their code varies in only few, minor positions.
You already sketched this as your option 2, and also already highlighted that it is the least optimal solution for your scenario. Code duplication is never welcome. The more so since your web service calls vary only slightly, in some method name.
In summary, this pattern is rather poor, and you shouldn't actively choose it. It usually comes into existence on its own, when people start with variant a, and months later add a variant b by copy-pasting the existing class, and then forgetting to refactor the code to get rid of the duplicate parts.
Strategy pattern
This design is commonly known as the strategy design pattern. Create one interface if_export, and one abstract class cl_abstract_webservice_export that implements the interface and includes most of the web service-calling code.
Except for this detail: The name of the method that should be called is not hard-coded but retrieved via a call to a protected sub-method get_service_name. The abstract class does not implement this method. Instead, you create sub-classes of the abstract class, i.e. cl_concrete_webservice_export_variant_a, cl_concrete_webservice_export_variant_b, etc. These classes implement only the inherited protected method get_service_name, providing their concrete needs.
Major advantages are that this pattern completely avoids code duplication, is open for further extensions, and has been employed successfully in lots of framework implementations.
Major disadvantage is that the pattern starts to erode when the first variant arrives that does not completely fit, e.g. because it does not only vary the method name, but also some parameters. Evolving then requires in-depth redesign of all involved classes, which can amount to considerable cost. Another disadvantage is that the inheritance setup can make it cumbersome to write unit tests: for example, unit-testing the abstract class requires to make up a test double that sub-classes it and overwrites the protected method with sensing and mocking code - all possible but not as neatly as with interfaces between the classes.
You already sketched this as your option 1. In summary, I would recommend to choose this pattern if you have control over all involved classes and are willing to spend some extra-effort to keep the pattern clean in case it doesn't fit completely.
Composition
Composition means avoiding inheritance in favor of loose interaction between indepdent classes over classes. Create the interface if_export and individual concrete implementations of it as cl_webservice_export_variant_a, cl_webservice_export_variant_b, etc.
Move out the shared code to a class cl_export_webservice_caller that receives whatever data and variant (e.g. method name) it needs. Let the variant classes call this shared code. To complete the class design, introduce another interface if_export_webservice_caller that decouples the variants classes from the caller class.
The major advantages are that all classes are independent from each other and can be recombined in several different ways. For example, if in the future you need to introduce a variant X that would call its web service in a completely different way, you can simply add it, without having to redesign any of the other involved classes. In contrast to the strategy pattern, writing unit tests for all involved classes is trivial.
There are no real disadvantages to this pattern. (The seeming disadvantage that it needs one more interface is not really one - object orientation has the aim to clearly separate concerns, not to minimize the overall number of classes/interfaces, and we shouldn't be afraid to add more of those if it adds clarity to the overall design.)
This option sounds similar to the option 3 you sketched, but I am not 100% sure. Anyway, this would be the pattern I would vote for.
This is an opinion-based question, so chances are it will be deleted.
Let's say I have class Teacher and class Course. I want to create method GetCourseId(TeacherId) that will receive as input parameter a TeacherId and will return a CourseId.
Should this method be in class Teacher or class Course?
I guess my question is that if there's a method that can fall under any number of classes, where should it finally go? Is there some unspoken rule for that?
Thanks.
I've often seen a third class created to handle something like this, where a method requires knowing about 2 classes and it doesn't quite fit in either.
In this case, it'd be the creation of a CourseManager that could contain methods like GetCourseId, GetCourseByTeachers, AddCourse, and other 'admin' tasks.
Many of these would serve as a wrapper of sorts -- CourseManager.AddCourse would likely pass a lot of work off on the Course constructor.
Normally i define classes like Teacher, Course as java beans which just hold fields, getters/setters and some very basic methods which directly use the fields and don't include any business logic.
Based on the supported functionalities/features in my application, i create business/manager classes which implement my business through communicating with the other java beans.
So if i'm creating a simple course registration application for a university, I would define 3 java beans: Teacher, Course, Student in addition to some manager classes based on the features that i want to support in my application i.e. in our case RegistrationManager which would hold methods like: registerStudentInCourse(), getStudentCourses(), addCourseTeacher() ..
Please note that I'm just sharing my way of coding, people may or may not agree with it.
The simplest solution will be having a property like
private Course course
or
private Set<Course> courses
based on cardinality (OneToOne or OneToMany) in Teacher class. It could be ManyToMany as well depends on the requirement and data modeling. You can get or set course/s assigned to the teacher using getter/setter method.
Apart from this if the relation is bidirectional than you can have similar property in Course class. In case of bidirectional mapping you can have utility method like registerCourse in the Teacher class which will set proper relations between entities.
public boolean registerCourse(Course course){
this.course = course;
course.setTeacher(this);
}
You can have this kind of utility method in Course class as well.
Suppose I am using TDD to create some class A. After I am done and have a "green" bar, I decide that I want to extract some class B with only static methods from class A using some refactoring tool. I now have class A and class B both fully unit tested, but only through the test class for class A. Should I also now create a test class specific to functionality of class B, even though that would be duplicating test?
As always, it depends on your context. What do you care about?
Overall behaviour
If you're building a system for internal use, or even a public (web) service, where the software you're shipping is the entire system, you don't have to care too much about a single class. If you're building a system, then test the system.
As long as it's covered by tests, you know that your system behaves correctly. However, you may run into a situation that after some months, you realize that you no longer need the original A class, so you delete it and its corresponding unit tests. This may cause test coverage of B to drop, so it may be a good idea to keep an eye on code coverage trends.
Unit behaviour
If you're building a (class) library, or framework, you're shipping each public class as part of the product. If you have multiple users of your library, you'll need to start thinking about how to avoid breaking changes.
One of the most effective ways to avoid breaking changes is to cover each class by unit tests. As long as you don't change the tests, you know that breaking changes are unlikely if all tests are green. However, that requires that you test all your public classes and members.
Thus, if you extract B to a public class, it's now a class that other consumers may depend on, and it would be a breaking change if you change it. Therefore, you should cover it with new tests. If you're building a unit, then test the unit.
From what you have described the answer is to create another new test. If either changes by you (or someone else who is not familiar with the "shared test") the other class will in no longer be tested.
If this seems wasteful, put the common test code in a third class...
I have the following health club scenario (coded in C++ BTW):
I want to create random Guest and Trainer objects (so both would have names randomly generated, but the guest would also have random health data).
I want to be able to make a lot of different random generators of differing complexities.
So clearly both would need the random forename/surname generator functionality - but I'm not sure how I can keep this code in one place.
I could have an abstract factory with all generation methods (e.g. generateForename()) in it that all the objects that require random generation can use. But should a trainer have access to a factory that can generate health data even though it has nothing to do with them?
I also thought about having an abstract factory for each class - so one for person, one for customer, one for guest and have objects generate their superclasses by passing them the appropriate factory but that sounds over complex for the situation.
I am fairly new to this so forgive me if my design is a bit off.
What do you guys suggest?
I'm not sure an Abstract Factory is what you're looking for. An Abstract Factory works best when you have the same base class but you need to create different concrete instances. Although you have the root base class of Person, you actually need to create derivatives of two, different base classes.
I would endeavour to keep the methods that generate data together with the class that contains that data. This way it can be reused.
Could you create a factory method on Guest and Trainer that would then be able to use the methods in their respective base classes to generate the data? Maybe create test-specific sub-classes to keep test stuff away from real stuff?
I see most projects creating separate factory classes, so for example, they'll have a User class, and a UserFactory class. This makes sense if your factory needs more methods than just a CreateUser method, but most of these factories only have a constructor and a CreateUser method (or equivalent for whatever the factory creates). So, are there other reasons why you would create a separate factory class over just adding a static User.create() method to classes?
In my experience, separate factory classes are mainly used if you often want to change the implementation, especially for test cases. For example, if User has methods that hit a database and are "too slow" for a Unit Test, you might want to have a MockUser that doesn't use the database. Then you can have a RealUserFactory for the actual app, and a MockUserFactory for the unit tests.
But there may be real world examples where you want to change, say from a SecurityClearedUser in your military spec app to a AnyOldUser in another. So a config file would declare the class of the factory, e.g. a MilitaryUserFactory or an AnyOldFactory.
Of course, User.create() could read the actual class to create from a config file. So, in practice, I'm not sure if there's that much of a difference. Depends on how things are setup.
Another thing to consider is 'separation of concerns'. In the case of User.Create, the user class will be doing more than it should, hence the need of a class that does precisely that, creating a User.
By using User.Create, you would have coupled the creation of an object to the class itself and in other instances, you will be confronted by scenarios were the user creation consists of various steps, and if that is the case, the User.Create method becomes inappropriate.
So to be brief, keep the user object responsible for being a user, and outsource the creation of the user to an external concern, Factory.
and from a readability perspective, User.Create vs UserFactory.Create... think of it as 'a car cannot create a car', but a factory can.