First Blog post for the capstone!
As my final semester approaches here at Worcester State University, I figured a relatable blog topic would be the best practices you can learn as a Software Engineer. The article can be found here: http://www.excella.com/insights/best-software-engineering-practices
This article touches upon three different practices that the author thought highly enough to include. The three practices are S.O.L.I.D., Automated Unit Testing, and continuous integration.
S.O.L.I.D. – an acronym for an object oriented design principle.
S – Single Responsibility – a class should have only a single responsibility.
O – Open/Closed Principle – Software should be open for extension, but closed for modification.
L- Liskov substitution principle – objects in a program should be replaceable with instances of their subtypes without altering the correctness of that program.
I- Interface Segregation Principle – Many client-specific interfaces are better than one general-purpose interface.
D- Dependency inversion principle – One should depend upon abstractions, not concretions.
When you use all of these principle together, a developer can create code that is much easier to maintain and improve over time. The code is SOLID.
Automated Unit Testing
Automated unit testing is a software development and testing approach where you independently test units to ensure that they are operating correctly. Unit testing can be done manually and it was in the past, but automation has taken over and everyone is thankful for that.
I use JUnit in eclipse to test java programs continuously. It makes it very easy to track where there is an error and what caused it to happen.
Developers become much more confident in their work when they don’t have to worry about wasting a bunch of time finding errors, instead we test immediately and fix the problem before it gets too clustered.
Continuous Integration quite literally means that you continuously ingrate the code and fixing issues before they are submitted to the actual project repository. In my classes we used Github or GitLab to manage repositories.
It works by a developer checking new code submissions in the repository. The integration process then builds and runs tests while analyzing the code. The CI detects any problems with the code and gives feedback to the developer. The developer fixes them and then approves the changes to the code. This way no code ever gets broken.
One of the benefits about using Continuous integration is that the version control system holds all current and changed code. You can easily go back to see what changed and how something may have broke.
In class we did a group activity which had us work together in teams of five and conduct a software technical review. In a software technical review you have a specific role in which you must fulfill specific duties. There are four roles. The producer, review leader, recorder, and reviewers.
Producer– The producer is the person who created the work that is being reviewed.
Review Leader– The review leader schedules the review meetings, prepares materials for meetings, conducts meetings, and writes the review report.
Recorder- The recorder’s job is to take notes of what is being said. They also document anomalies, decisions and recommendations.
Reviewer– The reviewer(s) job is to prepare an individual reviewer issue sheet that is given to the review leader before the meeting. The sheet contains all of the issues that the reviewer found with the code.
There are three different types of software technical reviews. The walk through, technical inspection and an audit.
Walkthrough- A walkthrough is an informal meeting with the producer and the colleagues. There is little preparation and little documentation.
Technical Inspection- A technical inspection is a formal process and includes training. There is sufficient and budgeted preparation time and the team ic very carefully selected.
Audit– An audit is a review that is held by an external group. The purpose of audits are to ensure that you are conforming to standards.
Why would we waste our time with such a complicated process when we could just look for faults individually? Well, there are many good reasons why we hold reviews and why the process is so important.
Reviews push developers to communicate with one another, it gives an opportunity to train new employees, it helps management report progress in the business, you find defects, it builds team morale and it gives the customer reassurance that the product comes out the way it should.
Going into your first review is probably nerve wracking. If you can remember the proper review etiquette, you should be golden!
Be prepared– There is nothing worse than an unprepared team member
Be respectful- it is the golden rule after all. Review the product not the producer.
Avoid discussions of style- Not everyone likes the same thing you do, as long as it is not wrong leave it be.
Provide minor comments to producer at the end of meeting
Be Constructive- help others, don’t bring them down.
Remain focused- identify issues and don’t try to solve them yet.
Participate- Do not try to get the spotlight, it can be annoying.
Be open- the results of the review should be available to the entire organization.
My source of information was our class slides, but you can learn more about software technical reviews here:
Have you ever watched a movie where the main character is involved in some crazy action scene, like getting thrown through a glass window or rolling over a car? The actor playing the main character is not actually doing that stuff. It is a stunt double made to look like the actor and is specialized in doing the crazy stunts. What does this have to do with Unit Testing? Well, sometimes we work on a project with other people and the part we need to finish our portion of the program is not done yet, we need a stunt double. These stunt doubles we use in unit testing are fakes, mocks and stubs.
What’s the difference?
Fakes- A fake is an object that is has working implementations that are usually different from the production code. A fake would cut corners to get to the data and return it back to the class calling it. Using an in-memory database would be a good way to take advantage of fakes.
Mocks- Mocks are objects that register calls they receive. They are pre-programmed with specifications on what is supposed to happen when the method is called. Mocks are useful for when you need to test the behavior of a code rather than a result. For example, if you are testing an instant messaging application on the iPad you don’t want to have to send out a message for every single test you run. Instead you would create a mock object that verifies that the program instructed the message to send. This is testing the behavior of the program.
Stubs- A stub holds predefined data and returns it when called. We use stubs when we don’t want to touch the real data. or can’t. You create stubs and have them return a value that isn’t going to change, so you know exactly what the resultss should be when testing. For example, in class we talked a lot about classes named “Student”, “Grade”, and “Transcript”. We acted as though the transcript class was being written by a classmate and we were required to write tests for the Student and Grade classes without the real Transcript class. We were able to do this by creating a stub transcript class that return the information that we would expect in our tests. This is a way of checking that the method is still being called and that it works the way we want it to.
You can read more about this here:
Last week I wrote a blog highlighting some of the things you can do to produce cleaner test code. This week I want to dive into one of those tips and explain it a little further so that you can use it in your code as well. This tip refers to the structure of test code to make it easier to read and understand, leading to easier maintenance. The blog I used as a reference is found here: https://blog.codecentric.de/en/2017/09/given-when-then-in-junit-tests/
I chose this blog because it highlights how to name test cases and how to prepare test objects for your test cases which is important in J-unit testing, especially when you are working on a team and need to leave clean test code so that others understand the purpose of them.
Getting started, JUnit testing can be confusing to look at if you don’t understand Java code in general. However, our goal should be that people who don’t code should still understand what our test is doing. In order to achieve this, we need to start with proper documentation of JUnit test code. Your code should have a header comment that explains exactly what your code is testing for. Like so:
Next you want to split up the test method into a more readable fashion. This is where the Given-When-Then tip shines:
This way you can easily read what is going on with the test. This can still be improved drastically. The test name is testIsPalindrome(), this is not acceptable as it doesn’t actually tell you what the test is doing. Try to summarize the purpose of the test in the test name.
This is a better name for our test method for obvious reasons. But our test case still uses String s for the string we are checking and our variable result is just as vague. The following example is a much more readable test case than our beginning product:
When we use names that actually refer to what is happening, it makes the entire test case easier to read. Again, this is important when writing JUnit test cases because you must be able to work together as a team and leave behind proper documentation which will prevent others from getting confused when reading your code. Notice how you can read the assert line almost as if it was saying “Assert that the string Worcester is not a palindrome.” If you can write test code that is as black and white as this then you shouldn’t have a problem when working with a team or even referring back to old code.
After learning more about JUnit testing I found this blog that really emphasized what we can do to keep our test code just as clean as our program code. You can find the blog here: https://blog.codecentric.de/en/2016/01/writing-better-tests-junit/
The beginning of the blog goes through the value of testing code and the importance of living documentation to help people that join your team half-way through a project. You should read that part if you want to, but my main focus of this blog is the basis of keeping the testing code clean and understandable so that people can understand what is actually going on.
One way to write better test cases in JUnit is to test behaviors and not implementation. Writing test cases based on implementations will lead to fragile tests that break easily. The blog gives the definition of behavior as “the range of actions and mannerisms made by individuals, organisms, systems, or artificial entities in conjunction with themselves or their environment”. I could not find a better way to word it then what the blog had here: “”Range of actions and mannerisms” – this explicitly limits our view to what is observable from the outside. If we refrain from disclosing internals, and phrase our tests accordingly, they should become much more flexible, and enable us to refactor, replace and/or rewrite large parts of the production code without additional effort” Essentially, we shouldn’t be testing specific variables but rather the universal behavior of the methods on their environments.
Another helpful technique to make your tests look as clean and understandable as possible is to group the tests by context. This means that you write your tests in a type of hierarchy. In the blog they use the form “Given-When-Then” meaning you should write your tests in a hierarchy like this:
This creates a tree of tests in the JUnit Runner window like this:
This is a huge tip to keeping testing code clean and easy to read, which I had not known about previously.
Single Assertion Rule
This is another tip that will certainly help me keep my tests cleaner because I had not heard of this before. The single assertion rule is just a way of saying that you should only have a one Assert.assertEquals(). This is because it makes looking for why the test failed that much easier, only looking at one value instead of two or more assert values.
This one has always been important. Make sure to use descriptive names rather than generic variable names like “x”, “data”, “input”. For example you could use “inputFromEveryDataFile” to improve on the name “input” if you were actually reading all the data from every file.
There are many more…
There are many tips out there to writing more clean and readable test code for JUnit. I couldn’t possibly document every single one! There is no such thing as code that is “too easy” to read so keep cleaning!
We recently went over how to test our programs and code using decision table testing. Decision table testing is extremely useful for laying out the requirements and conditions so that it is easier to comprehend and understand. This blog goes over, in detail, how to set up a decision table for a problem with an ATM and what conditions must be met to withdraw money. You can find it here: http://reqtest.com/requirements-blog/a-guide-to-using-decision-tables/ (I also used their pictures.)
I chose this blog to share with you because it relates directly to the assignment we were given for decision table testing. It has a section before the steps that give you the advantages and disadvantages to using the decision table which I thought would be useful to know and highlight. It also has every step for creating a decision table and is easy to understand.
“One advantage of using decision tables is that they make it possible to detect combinations of conditions that would otherwise not have been found and therefore not tested or developed. The requirements become much clearer and you often realize that some requirements are illogical, something that is hard to see when the requirements are only expressed in text.” – Ulf Eriksson, ReQtest
This advantage to decision table testing is a big one. Being able to easily cover every single case without being confused is extremely helpful. Essentially, decision tables give you a visual to go with the words.
The disadvantage to using decision table testing is that the decision table does not represent the complete test cases. Meaning you will have to think a little harder about how you write your cases.
With this being said, decision table testing can be used anywhere and this blog stresses that the tables should be constructed during system design so that the designers and testers are able to take advantage of the tables.
The steps are pretty easy to creating a decision table, the blog goes into more details with pictures (I recommend checking it out).
First, you want to figure out the conditions and actions in your problem. Conditions will be a requirement while actions will be the thing that happens if specific requirements are fulfilled.
Second, You want to figure out how many rules you are going to have. This is found by 2^n where n is the number of conditions in your table. Your going to want to fill out your table with the different possibilities of conditions being true/false.
Third, you want to reduce your table by combining redundant cases. The “-” means that you don’t care if credit is granted sense you have enough money in your account regardless.
Notice how Column 1 and 3 were the same? Now they are combined.
This is the final table you would use to write test cases for this program! Overall, Decision Table Testing is a great way to lay out all requirements in front of you to ensure you do not miss any possible combinations of input!