...
Code Block |
---|
. ├── fruit │ └── fruit.f90 ├── mod ├── src │ └── main │ └── <your_module>.f90 └── test ├── <your_module>_test.f90 └── <yourfruit_driver_name>.f90 |
- fruit.f90 - fruit source code.
- mod - directory used to store .mod files.
- <your_module>.f90 - your actual module.
- <your_module>_test.f90 - file with unit tests for your module.
- <yourfruit_driver_name>.f90 - file with test driving program. Filename could be anything, just remember it so you can use it while compiling and running project.
Install requirements
- You can change this file name, but remember to modify Makefile, so it could find it.
Install requirements
Load gfortran
Code Block |
---|
module load itm-gcc/7.3.0 |
Setup fruit library
...
Download fruit.f90 https://github.com/mortele/FRUIT/blob/master/src/fruit.f90 and put it into . into .<project_dir>/fruit directory.
Code Block |
---|
cd <project_dir>/fruit
wget https://raw.githubusercontent.com/mortele/FRUIT/master/src/fruit.f90 |
NOTE: While compiling fruit.f90 an error "Logicals must be compared with .eqv. instead of .eq." may occure. In this case you will need to modify fruit.f90 lines 912 and 913 editing ".eq." to ".eqv.".
Create project files
Create file with unit tests
...
Code Block |
---|
!file: <project_dir>/test/calculator_test.f90 module calculator_test use fruit contains subroutine test_calculator !use <your_module_name> use calculator integer :: result !test add subroutine call add (2,2,result) call assert_equals(4,result) end subroutine test_calculator end module calculator_test |
Create unit test driver
Create file named <yourfruit_driver_name>.f90. It will call your tests and handle fruit init and summary. You will need to modify it everytime you add new tests.
Code Block |
---|
!file: <project_dir>/test/fruit_driver.f90 program fruit_driver use fruit use calculator_test call init_fruit !if you want to generate XML result !call init_fruit_xml call test_calculator !call fruit_summary_xml call fruit_summary end program fruit_driver |
Create Create your module
Create file named <your_module>.f90 and put it into ./scr src directory. This file will be tested by module created in step 3.1.
Code Block |
---|
!file: <project_dir>/src/calculator.f90
module calculator
implicit none
contains
subroutine add(a,b,output)
integer, intent (in) :: a,b
integer, intent (out) :: output
output=a+b
end subroutine add
end module calculator |
Create your main program
Create file named main.f90 and put it into ./src directory. We won't use this file, but it is needed to compile and build calculator executable.
Code Block |
---|
!file: <project_dir>/src/main.f90 program main use calculator integer :: result call add(2,2,result) end program main |
Finalization
Create mod directory
This directory will contains built modules. Unlikely GNU make will not create it itself.
Code Block |
---|
cd <project_dir>
mkdir mod |
Create Makefile
It is a build instruction that makes compiling your project easy.
To use this code without modification you will need to follow convention:
- Put your tests in /test directory and name them *_test.f90
- Name your main program main.f90
- Name your test driver "fruit_driver.f90"
Otherwise you will need to modify some of it's lines.
Code Block |
---|
#file: <project_dir>/Makefile
C=gfortran -O3
FFLAGS=-c -J ./mod
OBJS=$(patsubst %.f90,%.o,$(wildcard src/*.f90))
TESTED_OBJS=$(filter-out src/main.o, $(OBJS))
TESTS=$(patsubst %.f90,%.o,$(wildcard test/*test.f90))
LIB=$(patsubst %.f90,%.o,$(wildcard fruit/*.f90))
DRIVER_SOURCE=test/fruit_driver.f90
DRIVER_OBJ=$(patsubst %.f90,%.o, $(DRIVER_SOURCE))
all: run
run: $(OBJS)
@echo "Building executable"
$(FC) $(OBJS) -o $@
$(OBJS): src/%.o: src/%.f90
@echo "Compiling objects"
$(FC) $(FFLAGS) $< -o $@
test: fruit/fruit.o $(TESTED_OBJS) $(TESTS) $(DRIVER_OBJ)
@echo "Building executable"
$(FC) $^ -o run_test
$(TESTS): test/%.o: test/%.f90
@echo "Compiling tests"
$(FC) $(FFLAGS) $< -o $@
$(DRIVER_OBJ): $(DRIVER_SOURCE)
@echo "Compiling driver"
$(FC) $(FFLAGS) $< -o $@
fruit/fruit.o: fruit/fruit.f90
@echo "Compiling FRUIT library"
$(FC) $(FFLAGS) $< -o $@
clean:
rm mod/*.mod -f
rm src/*.o -f
rm test/*.o -f
rm fruit/*.o -f
rm run -f
|
Run tests
Code Block |
---|
cd <project_dir>
#to compile and run tests
make test
./run_test
#to clean after build
make clean
#to compile and run you program without tests
make
./run |
Using Using setup and teardown subroutines
NOTE: This step is optional and is needed to be done only if you want to use setup and teardown subroutines.
NOTE: Using setup and teardown subroutines with this library is complex and unellegant. Consider using another framework or FRUIT+Ruby version.
Add setup and teardown subroutines
First you need to define setup and teardown routinessubroutines.
Code Block |
---|
!file: <project_dir>/test/calculator_test.f90 module calculator_test use fruit contains subroutine setup !... end subroutine setup subroutine teardown !... end subroutine teardown subroutine test_calculator use calculator integer :: result !test add subroutine call add (2,2,result) call assert_equals(4,result) end subroutine test_calculator end module calculator_test |
...
Code Block |
---|
!file: <project_dir>/test/fruit_basket.f90 module fruit_basket use fruit contains subroutine calculator_test_all_tests use calculator_test call setup write (*, *) " ..running test: test_calculator" call set_unit_name('test_calculator') call run_test_case (test_calculator, "test_calculator") if (.not. is_case_passed()) then write(*,*) write(*,*) ' Un-satisfied spec:' write(*,*) ' -- calculator' write(*,*) call case_failed_xml("test_calculator", & & "calculator_test") else call case_passed_xml("test_calculator", & & "calculator_test") end if call teardown end subroutine calculator_test_all_tests subroutine fruit_basketbasket1 call calculator_test_all_tests end subroutine fruit_basketbasket1 end module fruit_basket |
Pay attention to code lines presented below. They come from code above. You can use them to call tests from desired test module.
...
Now test subroutines calls are moved from test_driver to test_basket. You need to import test_basket module and call its it's main subroutine. In this case it is "fruit_basket" subroutine.
Code Block |
---|
!file: <project_dir>/test/fruit_driver.f90 program fruit_driver use fruit use fruit_basket call init_fruit call fruit_basketbasket1 call fruit_summary end program fruit_driver |
Run tests
This bash code will compile all source codes and run tests described in ./test/calculator_test.f90 file.
Modify Makefile
Add lines presented below at the end of the Makefile.
Code Block |
---|
test/fruit_basket.o: test/fruit_basket.f90
@echo "Compiling FRUIT basket file"
$(FC) $(FFLAGS) $< -o $@ |
Also you need to modify this line:
Code Block |
---|
test: fruit/fruit.o $(TESTED_OBJS) $(TESTS) $(DRIVER_OBJ) |
as follows:
Code Block |
---|
test: fruit/fruit.o $(TESTED_OBJS) $(TESTS) test/fruit_basket.o $(DRIVER_OBJ) |
Code Block |
#filename: build_run_and_clean.sh
#create mod directory if not exists
mkdir -p mod
#compile source files
# -J specifies where .mod files will be generated, and add this path in compiler search location
gfortran -c ./src/*.f90 -J ./mod
gfortran -c ./fruit/*.f90 -J ./mod
gfortran -c ./test/*.f90 -J ./mod
# create executable file
gfortran -o fruit_driver *.o
#run tests
./fruit_driver
#clean
find . -name "*.o" -type f -delete
find . -name "*.mod" -type f -delete |
Example output
Output created with project described above
Output created with different project
...